8000 GitHub - BITNP/waycast: 道枢(Waycast)—— 树莓娘唯一核心:微服务化 Agent,输入/输出模块经 wire 契约接入 · GitHub
[go: up one dir, main page]

Skip to content
BITNPPublic

About

道枢(Waycast)—— 树莓娘唯一核心:微服务化 Agent,输入/输出模块经 wire 契约接入

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

道枢(Waycast)· 树莓娘唯一核心

关联项目:云和(Aria) · 机杼(Loom) · 显影(Lumen)

一个基于 LangChain v1 的微服务化 Agent:输入/输出模块是独立服务,通过 WebSocket 连接到 Agent(枢纽),以统一 JSON Wire 协议交换帧。每条输入触发一次 Agent 调用(Invocation);Agent 通过多轮真实模型工具调用产出 JSON 输出单元列表(可为空),派发给已连接的输出模块连接(fire-and-forget);每个派发立刻返回输出结果,该结果搭载在下一轮调用的输入消息开头、一次性进入对话历史(ADR-0002 / ADR-0014)。

本文是用户文档:如何安装、配置并运行 Waycast 服务。架构细节、Wire 协议与模块编写、测试与代码结构见开发者文档 DEVELOPMENT.md;术语见 GLOSSARY.md,架构决策见 docs/adr/。

Waycast 是什么

Waycast 的核心(src/)只含本体:协议、Agent、hub、service、wire 帧模型。模块一律作为网络客户端运行在进程外(ADR-0008),src/ 中不存在任何 mock 或占位。

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  输入模块     │    │  Agent/Hub  │    │  输出模块     │
│ (独立服务)    │───▶│  (Waycast)  │───▶│ (独立服务)    │
└─────────────┘    │  /ws/modules │    └─────────────┘
                   └─────────────┘
   所有帧走同一条多路复用 WebSocket 连接(A25)

核心概念

  • Input module:把外部信号转成统一 UnifiedInput(content + source + metadata)的独立服务,经 WebSocket 发送 input 帧;每条输入恰好触发一次 Invocation。
  • Agent:对每条输入运行一次多轮工具调用(内置真实工具 + 可接入 MCP 工具),产出结构化 JSON:{ "units": [ { "module": "...", "payload": {...} }, ... ] },units 可为空。
  • Output module:连接时声明自己接受的 JSON Schema 与语义描述;收到 output_unit 帧后立即返回 result 帧(成功/失败)。Agent 在派发前按 schema 校验(ADR-0008)。
  • 闭环:模块返回的 result 帧进入待送达 feed,恰好在下一轮 Invocation 开始时被一次性取出,搭载在该轮输入 human 消息的开头进入对话历史(每条结果只出现一次,随摘要老化)(ADR-0002 / ADR-0014)。
  • Global memory:所有输入以 human 消息累积到同一条对话历史(固定 thread_id + InMemorySaver),单消费者逐条处理,无会话隔离(ADR-0005);历史逼近阈值时由内置 SummarizationMiddleware 自动摘要压缩(ADR-0013)。

快速开始

安装

依赖用 uv 管理,Python ≥ 3.12:

uv sync --locked

配置

复制 .env.example 为 .env 并填入真实凭据(.env 已被 .gitignore 忽略):

export WAYCAST_BASE_URL="https://your-provider.example.com/v1"   # 或 OPENAI_BASE_URL
export WAYCAST_API_KEY="sk-..."                                  # 或 OPENAI_API_KEY
export WAYCAST_MODEL="deepseek-v4-flash"                          # 可选,默认 gpt-4o-mini
export WAYCAST_HUB_TOKEN=""                                       # 可选,模块连接 token(空则关闭鉴权)

其他可选变量:

变量 默认值 说明
WAYCAST_QUEUE_SIZE 100 输入队列容量(背压上限)
WAYCAST_HOST 0.0.0.0 监听地址
WAYCAST_PORT 8000 监听端口
WAYCAST_THREAD_ID waycast-global 全局记忆的 thread_id
WAYCAST_AGENT_CONFIG waycast.prompt.txt 用户系统提示词文件路径(纯文本)
WAYCAST_LOG_LEVEL INFO 本服务日志级别(DEBUG 输出输入帧、LLM 请求/响应、单元派发与 result 帧等调试信息)
WAYCAST_DEPS_LOG_LEVEL WARNING 第三方依赖日志级别(httpx/openai/websockets 等;uvicorn 访问日志仅在放开到 INFO/DEBUG 时才输出)
WAYCAST_LLM_LOG_MESSAGES incremental LLM 请求消息的记录方式:incremental 只打相对上次请求新增的消息,full 每次全量打印(历史前缀变化时自动回退全量)
WAYCAST_LLM_TIMEOUT 120 单次 LLM HTTP 请求超时(秒);挂死的 provider 请求快速失败进入错误日志,不再按 openai SDK 默认 600s 静默阻塞整轮调用
WAYCAST_LLM_MAX_RETRIES 1 LLM 请求的 SDK 重试次数(openai SDK 默认为 2,叠在超时之上)
WAYCAST_LLM_REASONING_EFFORT 空 LLM 思考档位,走 ChatOpenAI 原生 reasoning_effort 标准参数(官方自 langchain-openai 1.4.1 提供);空则不发该字段。如 none(实测 maas.bit.edu.cn deepseek-v4-flash 默认开思考,置 none 后 llm response usage 行的 reasoning_tokens 归零)
WAYCAST_LLM_EXTRA_BODY 空 逐请求透传给 LLM 端的额外 JSON 字段(ChatOpenAI 官方一等字段 extra_body,官方推荐用它传 provider 专属方言参数);思考档位优先用 WAYCAST_LLM_REASONING_EFFORT,此处同名键会被自动剔除

自定义 Agent 系统提示词

你可以直接写 一整段纯文本 作为 Agent 系统提示词的用户部分。默认读取项目根目录的 waycast.prompt.txt(可用环境变量 WAYCAST_AGENT_CONFIG 指定路径),文件内容原样读入,无需 TOML、转义或字段结构。waycast.prompt.txt 是个人本地配置,不入库(已在 .gitignore 中);从仓库自带的示例模板 waycast.prompt.txt.example 复制一份开始修改即可。

你是一个调度助手。

使用场景:接收输入,把结论交付给已连接的输出模块。

注意:
1. 涉及时间时先调用 get_time 工具;
2. 回复要简洁,避免啰嗦。

文件内容拼在自动生成的 capability catalog(每个连接模块的 describe 与 JSON Schema)之前,构成最终系统提示词:

[固定 base prompt] + [你的纯文本提示词] + [自动生成的模块目录 + schema + 状态工具] + [默认规则]

协议规范始终保留在提示词里;你只写角色、场景与行为要求。文件缺失或为空时,系统提示词保持默认不变。

启动服务

uv run --locked waycast serve

服务提供:

  • WS /ws/modules —— 模块连接唯一入口(所有输入经模块 input 帧进入)。
  • GET /health —— 健康检查,返回 queue_size。
  • GET /results —— 最近一次调用的完整结果(units、各派发的 OutputResult)、pending_output_results、已连接模块与队列大小;无输出模块时被跳过的输入记录在 last_skipped。

运行参考模块

启动 hub 后,在另一个终端用示例模块连接它(--hub 指向 hub 地址、--token 与 WAYCAST_HUB_TOKEN 一致):

# 输入模块:每 60 秒推送一条当前 UTC 时间
PYTHONPATH=src:examples .venv/bin/python -m waycast_examples.cron_source --hub ws://127.0.0.1:8000 --interval 60
# 输出模块:接收 units 写日志
PYTHONPATH=src:examples .venv/bin/python -m waycast_examples.log_sink --hub ws://127.0.0.1:8000
# 输入+输出、带状态查询的演示模块(stdin 输入、stdout 回声)
PYTHONPATH=src:examples .venv/bin/python -m waycast_examples.echo_bell --hub ws://127.0.0.1:8000

hub 端口不是 8000 时用 --hub ws://127.0.0.1:<port> 指定;配了 WAYCAST_HUB_TOKEN 时每个模块都带上同样的 --token。

下一步

  • 想编写自己的输入/输出模块(wire 协议、capability 握手、status 查询):见 DEVELOPMENT.md。
  • 想理解关键设计点(单通道多路复用、背压、结构化输出回退等):见 DEVELOPMENT.md 与 docs/adr/。
  • 术语的唯一称呼见 GLOSSARY.md。

命名来历

waycast(道枢)——waycast 一名有两层来历。

其一是字面的双关:way(路、道)× cast——投送、播送(broadcast 的词根)、铸模、群戏卡司。输入沿路而来,被核心铸成一次次的表现。

其二是向 Wayland 协议致敬(ADR-0015 记录)。Wayland 是 Linux 桌面的显示协议,其核心洞见在官方文档里写得很干净:应用(client)自己渲染自己的 surface,「所需要的只是把画好的 surface 呈现出来、并在多个客户端之间接收与仲裁输入的一层」——这一层叫 compositor(Wayland Book, Introduction;wayland.freedesktop.org,二者查阅于 2026-11-10)。waycast 是同构的镜像:各模块像 Wayland 客户端一样只广告自己的 capability、只与中枢收发帧,从不直接对话;hub 像 compositor 一样只做两件事——接收并在所有输入之间仲裁(每个输入帧恰好一次 Invocation,话权归 Agent,ADR-0011),以及把输出组成后呈现出去。连命名形态都同构:Way+land 是「道之所栖」,Way+cast 是「道之所投」。

**中文名「道枢」**出自《庄子·齐物论》:「彼是莫得其偶,谓之道枢。枢始得其环中,以应无穷。」——枢,门轴也,是 hub 的中文本字;「环中」是圆环的空心处,立于其中便可应对外界的无穷变化。这恰好是三件事的合一:hub 立于输入与输出的环心,应答无穷的请求;圆环是 π——树莓娘的「树莓」兼指树莓派 Raspberry Pi,无限不循环恰似一场不会自我重复的对话;而「道枢」二字逐字对译 waycast:道=way,枢=hub。

关联项目(waycast 道枢 / aria 云和 / loom 机杼 / lumen 显影,multirepo 微服务)的命名与映射见 ADR-0015 与 GLOSSARY「关联项目」。

许可证

Copyright © 2026 北京理工大学网络开拓者协会(BITNP)。本仓库以 AGPL-3.0-or-later 发布(全文见 COPYING:SPDX):可自由使用、修改、分发;但修改版以分发或网络服务方式对外提供时,必须以同许可整体开源(AGPL 的网络条款)。

树莓娘(Raspberry Girl)名称、形象与相关美术资产为网协专有,不适用本许可证。

About

道枢(Waycast)—— 树莓娘唯一核心:微服务化 Agent,输入/输出模块经 wire 契约接入

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0