合并说明:本文是博客 bloodysky.top「庖丁解牛 Raven」8 篇系列文章的完整合并版。原 8 篇均发布于 2026-10-01,本文按原篇目顺序合并为一篇,正文内容忠实保留原文全部实质内容(结论、代码引用 file:line、清单、表格、代码块),未作删减或缩写;仅去除了每篇重复的系列导航(「《庖丁解牛 Raven》系列 第 N/8 篇」)、重复的站点页头页脚、以及重复的引言/作者介绍。原作者署名与版权信息见文末。
图 0 · Raven TUI 实况(v0.2.3,2026-10-03 摄于 WSL2 的 ~/work):启动即列出 40 个可用工具与 4 个技能。本系列的每条结论,都在这样一台实机上验证。
一、架构总览与工程美学
0. 结论先行
Raven 的本质是一个六层管道 + 两条总线:
1 | 消息总线(spine):TurnRequest → Lane(串行) → Runner → Sink → DeliveryHub |
六层自外向内:channels(入口)→ spine(调度)→ loop(ReAct 主循环)→ hook 横向切面 → tools/MCP(执行)→ subagent(fan-out)。
四个工程支柱声明在 raven/__init__.py:上下文管理(Curator)、主动性(Sentinel + cron)、token 效率(token_wise)、技能自演化(memory_engine/skill_forge——最后一个只是检索+反馈管道,真正的演化循环在外部 EverOS 进程,本系列第 8 篇专拆)。
最值得学的三个设计:
- origin 五种流通、一套管线——用户/cron/sentinel/heartbeat/subagent 全部汇入同一个
Scheduler.submit(spine/scheduler.py:571),差异只在并发池与旁路; - 注释即事实——几乎每个反直觉分支都带实测日期与踩坑叙事(”measured 2026-09-02” 类注释遍布全树);
- fail-closed / fail-safe 纪律——无主回合审批直接拒、渠道 probe 失败答 unknown 不答 disconnected、hook 异常隔离不停回合。
最值得警惕的三个点:
- subagent 异步续报是事件驱动不是定时——“等 40 秒”是墙钟幻觉(manager.py:2056-2058 明确禁止再排心跳,结果由
_announce_result→_inject提交spine.TurnRequest(origin=SUBAGENT)事件驱动生成); - sandbox 默认无隔离(且
is_sandboxed默认 True 反而会关掉宿主的 deny-list); - 本机 Sentinel 实际关闭,主动性只剩 cron,且重启会丢内存态队列。
1. 架构总览与运行拓扑
1 | 手机飞书 App ──WS 出站长连(无需公网)──> raven gateway (systemd user service) |
约 40 万行 / 48 个包,按角色分族:
| 族 | 包 | 行数量级 |
|---|---|---|
| 管线核心 | agent/(52K)、spine/(7.4K)、core/(3K)、session/(1.4K) | ~64K |
| 子代理 | agent/subagent/(26.7K)、agents/(33K 预设)、acp/(5.1K)、acp_client/(8.3K) | ~73K |
| 控制面 | cli/(24.5K)、rpc/(36.6K)、gateway/(1.1K)、ui/ | ~62K |
| 支柱 | context_engine/、memory_engine/、token_wise/、proactive_engine/(14.4K) | ~29K |
| 外部接口 | channels/(8.3K)、providers/(14.6K)、mcp/(4.1K)、browser/、a2a/ | ~29K |
| 横切 | agent/hook/(883)、permissions/(4.5K)、sandbox/、security/、tracing/、trajectory/(7.4K)、playbook/(7.7K)、eval_engine/、stint/(4.1K)、plugins/、skill_hub/、knowledge/、importer/、contracts/ | ~40K |
| 杂项 | templates/、i18n/、updates/、market/、ops/、utils/、auth/、routing/、observability/ | ~10K |
2. 三大组装点与进程模型
core/ 的哲学:每个入口只装配自己,共享部分才进 core。三个组装点并存:
| 组装点 | 位置 | 服务对象 |
|---|---|---|
build_gateway |
gateway/spine.py:211 | IM 渠道 + cron/sentinel/heartbeat + 页面双 spine |
build_rpc_stack |
rpc/bootstrap.py:139 | TUI / raven serve 页面 / acp worker(transport 无关) |
| CLI one-shot | cli(build_one_shot_spine) | raven agent -m 单发(不自建 MCP 连接→调 MCP 必败,by-design 竞速,见第 7 篇) |
generation 热切换(raven gateway reload):core/runtime.py:72-76 的 RavenRuntime 是冻结 dataclass,五个成员 {loop, plugin_registry, backend, strategies, deliverables} 身份不可变;FREEZE 只封成员身份,留了三个合法中途门:loop.apply_agents/apply_mcp_config/set_default_binding(runtime.py:48-60)。SwapCoordinator(:315-401)单次 swap、最小间隔 5s(:328)、generation 计数 release 自增(:386-396)。CLI reload 拒绝语义:busy(N 个 subagent + M 个 pending questions,--force 覆盖)/ build_failed(新配置失败时旧 generation 继续服务,gateway_commands.py:981-1025)。cut_by_reload 让被砍回合的用户至少收到一句”reload 截断了本回复”(gateway/spine.py:36,194-197)。
3. 工程美学:五条值得抄的设计原则
- 注释即事实:”measured: litellm DEBUG 146 KiB one line killed the agent loop”——每个反直觉分支都绑定一次真实事故与日期。读 Raven 源码等于读一部踩坑史。
- fail-closed 优先:无主回合审批=拒;probe 失败=unknown;渠道 probe 不可达=不说 disconnected;hook 崩=隔离;hook 停链=第一个短路者赢。
- 顺序即安全:先 chmod 后写 token;截断标记预算在帧前;drain 先于 stop;subagent 先于 spine 封;检查先于确认。
- 能力靠声明不靠猜:presence 非 truthiness(
{}即支持);can_steer 从_meta读、未声明不调;方言按 agentInfo.name 自选。 - 双读一切:control_* 与 web_* 双拼写;snapshot 指纹 + stale 标记;新旧 instruction 双读。
4. 脆弱点与风险清单(按严重度)
| # | 问题 | 位置/证据 |
|---|---|---|
| 1 | sandbox 默认无隔离,is_sandboxed 默认 True 反使 deny-list 对覆写执行器失效 | sandbox/init.py:38-105、interfaces.py:53-65;全包无 bubblewrap/seccomp |
| 2 | 渠道去重启丢(1000 FIFO 内存态)→ 同消息重投可能二次处理 | channels adapter :473-477 |
| 3 | Sentinel 本机关闭 + cron 重启丢内存队列(SystemEventQueue/WakeScheduler/notified) | proactive_stack.py:210-211;system_events.py:4-7 |
| 4 | feishu SDK 无限重连:stop 杀不断、restart 短暂双活 | channels 终报确认 |
| 5 | allow_from 默认 ['*'] ——谁能发消息谁驱动它 |
channels/allowlist.py:58-59(收紧:raven channels set feishu --allow-from <open_id>) |
| 6 | MCP schema 服务端原文透传,恶意/劣质 server 可控制模型工具面 | mcp/client.py:40 |
| 7 | 插件无沙箱(进程内任意 Python),tool_gates 绕过权限闸门 | plugins/manifest.py;registry.py:1046-1067 |
| 8 | CLI one-shot 调 MCP 必败(by-design 竞速),冒烟验证会被误导 | registry.py:664;prewarm fire-and-forget |
| 9 | skill watcher 守护线程在多次 spawn 时可泄漏 | skill_hub/catalog.py:195-201(自述) |
| 10 | traces 334M / tmp 48M 无自动 reclaim(acp-frames 才有 64MB/7 天策略) | ~/.raven 实测 |
| 11 | trust.py 仅提示词级包裹,无强制力 | security/trust.py:23-44 |
| 12 | session 续场不可用——编排系统自身的运维坑,实测连撞三次 | 本轮实测 |
5. 周边模块速览
- session store(1012 行):append-only JSONL + 每 save 追加 metadata(last-wins);跨进程合并三件套=锁 +
_file_stamp(size,mtime_ns) 脏检 + 三方合并——只有本副本改过的键才能盖过磁盘;list排序按 updated_at 刻意不按 last_message_at,因为三个 caller 取 [0] 决定投递路由(heartbeat/sentinel nudge/sessions list),为选择器重排序=静默改投递。 - eval_engine(683 行):三 hook 全默认 off 且 unwired——设计完备的演示引擎;AfterIteration 永不短路(”评审者只能 annotate 不能打断回复链”)。
- browser:file:/chrome:/devtools: 等导航全拒(file:// 能读出 gateway token,policy.py:21-28 自述);driver 共享 page + owner-tab 绑定 + 结构快照(拒绝让模型在 JPEG 里找按钮)。
- WhatsApp sidecar:channels/ 原生适配器之外的第二类渠道架构——外挂 Node 桥进程(Baileys 多设备协议,
ws://127.0.0.1:3001+ token 首帧认证),Python 侧管构建指纹与凭证隔离(TS 侧清凭证只删 .json 不删 token,防锁死桥接)。
6. 三条元教训
- 动手前先证伪任务书:本系列解剖中,多轮”按任务描述找文件”的预期与实物不符(trajectory 的 daemon.py、everos 的子包结构、stint 的半成品状态)——
ls + find + grep 空验证必须先于读码; - 注释即工程史:Raven 系代码的真实约束都长在注释里——假健康探测、无 owner 的 stint、不被重排的 session 列表;
- 断点比管道更值得记录:”设计了但没接线”的清单(feedback no-op、retire 缺失、Sentinel 关闭、sandbox 无隔离、eval unwired)才是系统的真实边界。
二、一条飞书消息的完整旅程
1. 十步管道全景
一条飞书消息从手机到回复,走完这十步:
- 入站:飞书 WS 长连只订阅
p2_im_message_receive_v1,去重在 adapter 内存 1000 条 FIFO——重启即失效(channels/feishu 适配器,实测确认的历史设计)。 - 准入:
allow_from六锚点(channel.py / intake.py / base.py / allowlist.py / manager.py / channel_commands.py),空列表=启动即 SystemExit(deny-all 致命,manager.py:157-163)。 - 转写:媒体走 Groq Whisper API(非本地模型,channels/feishu:376-431 + transcribe.py:15-23)。
- 提交:Intake →
Scheduler.submit(spine/scheduler.py:561-598)——全系统唯一入口,cron/sentinel/heartbeat/subagent/用户全部经此。 - 串行化:Lane 按 conversation 键(
tui:前缀归页面 spine,其余归 IM spine,gateway/submit_router.py:34-47——这里修过 2026-09-08 双 spine 同会话双车道事故:subagent relay 进页面会话跑网关 spine,turn.send guard 看不见,工具画两次结果送两次)。 - 执行:
_run_turn(scheduler.py:427)→ pools 按 origin 分流(user=4/system=2)→runner.run(req, emit, drain)。 - 循环:turn_path.py:605-2039
_run_agent_loop,四状态机_AWAIT_MODEL → _AWAIT_TOOL_RESULTS → _PREPARE_NEXT_TURN → _ENDED;核心约 956-1050 的大 while;工具批处理逐项错误隔离(一个工具炸不拖垮整批)。 - finalize:七阶段(统计→artifacts→session 落盘→学习→TurnEnded→Outlet 发→DeliveryHub)。
- 送达:DeliveryHub → ChannelOutletAdapter(gateway/outlet.py:41-72:Text→send;吃掉流事件——渠道非流式,吃不是失败;仅 ORGAN_DEGRADED notice 渲染;无附件能力的渠道降级成
Files ready: ...文本)。 - 失败面:TurnFailed →
_failed_turn_reply(gateway/spine.py:39-59):LLM 错误只报类别+端点,厂商账户(auth body 掩码 key、拒绝 body 引 prompt)只进 operator log——群聊里永远看不到供应商原文。
2. spine 调度层:一套总线,五种 origin
Lane 每会话串行(scheduler.py:321/331/391),提交注释写得很直白:”gateway hosts a mix of turns (cron/heartbeat/channel users) on one runner”(:429)。
| Origin | 池 | 特殊行为 |
|---|---|---|
| USER | user 池(4) | 交互 asker 绑定、on_user_inbound 全链 |
| CRON | system 池(2) | 回复读回(readback_texts,填 system event,gateway/spine.py:71,144-159);不触发 on_user_inbound;绑 cron-context guard |
| SENTINEL | system | 跳过 on_user_inbound;INTERRUPT/INJECT 降级 APPEND |
| SUBAGENT | system | 异步 announce 的载体;同上 |
| HEARTBEAT | system | 纯 fire-and-forget 不读回 |
无主回合 fail-closed:cron/sentinel/heartbeat 的 permission responder 故意绑 None,ask tier 拒绝并给原因(gateway/spine.py:123-126);allow_ask=False 时闸门拒 “this turn is not interactive”(permissions/gate.py:271-278)。delivery-only origin 不存储读回原文——注释原话 “would only leak (no one pops it)”,防长驻 daemon 累积。
3. 主循环:四状态机 + 五把压缩闸
- 每回合上限 5 把压缩闸(MAX_COMPRES_RETRIES=2 / IMAGE_DEMOTE=1 / IMAGE_STIR=2 / keep-3-tool-results / keep-1-image,agent/window/shrink.py:34-77)。
- 消息组装 9 因子:tool_kinds → system → 历史 → recall → skills → curator → personalization → routing → window。
- history 走 Curator 慢路径时不重复压缩——trimmer 预算与 window.shrink 是两套 make-fit 机制,经
available_history算术解耦,这是 context_engine 与 loop 的接缝陷阱(详见第 5 篇)。 - 改写/续跑入口:turn_path.py:3106-3116(跳过消息续跑)、2900-3106(新回合前奏)、3276-3330(分派出入,
turn.send一回合一会话 guard 所在)。
4. Hook 系统:883 行的反直觉集大成者
6 阶段(agent/hook/init.py:1-8):
1 | before_user_inbound(入站一次,只有这里 fresh roster) |
抽象(raven/contracts/loop_hooks.py):AgentHook(全 no-op 基类)、AgentHookContext(每回合状态、跨迭代 mutate、identity=回合)、HookDecision(short_circuit_result / rollback / modified_content / modified_tools / append_note / notes)。
CompositeHook(composite.py:49-188)的链纪律:
- 首个 short_circuit/rollback 立即停链——所以 Sentinel 的 decision_consumer 在入站短路 /pick 回复时,Personalizer 不会误分类(:11-14 自述);
- 内容链仅 after_send + before_user_inbound;工具链仅 before_iteration;
- 异常隔离:logger.exception + continue,单 hook 崩不停回合(:152-158)。
ParticipantHook(participant.py:110-496)是插件”参与者”上链的通道,一回合一实例:
_Row是拒写的 dict 子类——参与者只能靠 return 回答,不能改 transcript(:45-71);- roster 制:每阶段最后一个 seat 持全 roster 问一次,其余 no-op(:182-220);
- 9 动词映射 harness 四域(memory/planning/action/capability);
rolls_back_iterations类属性让 verdict 能把回合打回(loop 据此扣草稿门,:115);- system addendum 按文本 rfind 取回,防多 seat 副本叠加(:395-441)。
方法论注脚:本轮解剖初期曾假设 hook 是”do_hooks/filter_results 纯函数语义、10 分支分类法”——均被源码证伪。假设必须过 file:line 锚点,这是整个系列的方法论纪律。
三、Subagent 编排层与 stint 轮次
1. spawn 全链路(26.7K 行的 orchestration 层)
1 | SpawnTool.execute(spawn_tool.py:433-560) |
状态机:pending → running → completed/failed/cancelled/aborted,全量持久化;handle 锁包住 load→run→save 的全程。
以下三张实况截图来自 2026-10-03 两次真实的 DAG 任务——PiPhone「切题技能 v1」三节点(裁剪模块 / 切题指令分支 / 联调验证)与「复习本原图留存」三节点(本地排版 / 手机部署 / 实测回归)——正是上面这条 spawn 链路的运行态:
图 1 · run subagent dag 三节点实况:Raven-Code 本地实现 + PiPhone 同步手机并改调用方 + PiPhone 手机实测原图册并回归;每个节点的状态、归属 agent 与耗时实时可见,下方 spawn tree 同步展开。
图 2 · 单个 spawn 节点会话详情:PiPhone@integrate-test 已跑 38 条消息,v1.1「锚点升级接线」重试中——先零改动验证、失败回退保护、顺带改 single 文案,最后重启上线;节点内的思考、命令与返回预览都在主界面里可查。
2. 五个运维流言的源码裁决
这一节是”流言 vs 源码”的对质,每条都有锚点:
- 异步续报是事件驱动,不是 40s 定时。receipt 就是 manager.py:1070-1071 那句
Subagent [...] started (id: ...). I'll notify you when it completes.;续报由_announce_result(manager.py:2042-2133)→_inject(:2420-2470)提交spine.TurnRequest(origin=SUBAGENT)生成;manager.py:2056-2058 明确禁止再排心跳。”~40s”是被调方的墙钟时间(CLI agent 跑完 + announce 回合生成),不是任何定时器。
图 3 · 流言 1 的实况证据:节点结束后,bridge_branch.memory.json / crop_module.memory.json 由上游异步写入(”written asynchronously after a node finishes”),主 agent 据此续跑;底部 message PiPhone/integrate-test-37d8be · Enter to steer the running turn 即对运行中回合的实时转向。
- readyTimeoutMs = spawn → initialize 预算。透传链:acp_agent.py:1428-1429 →
pool.acquire(ready_timeout_s)→ pool.py:473;_HANDSHAKE_TIMEOUT_S=120是硬顶。opencode 30s / openclaw 45s(presets.py:181,189,ready 实测需 ~21.5s)/ 手机 SSH 桥 60s。 - 手机端 “executable not found (command: pi)” 是 cwd 误报。链:spawn_tool.py:537
workspace=workdir.current()→ manager.py:1738 effective_workspace → backend.run 的launch_cwd=self.cwd or str(workspace)/session_cwd=str(workspace)(acp_agent.py 客户端 :1436-1437)→ pool launch_key 含 cwd(pool.py:84-104)→ SSH launcher 把 WSL 的路径导出到 Termux → 手机上没有该目录,pi 启动即报 not found。代码自证注释:”Conflating them sent a pinned entry’s own folder to session/new”——launch_cwd 与 session_cwd 是两个东西。 - 三处持久化:
subagent_instances.json(instances.py:28/56-59,实测 kinds {acp:24, cli:20, dag-node:14})、subagent_acp_capabilities.json(capabilities.py:59/322-325)、subagent_sessions/(product_render.py:342)。 - ACP 绑定快照与 entry env 分开传(acp_agent.py:1429-1433):折进 env 会改 launch key,pool 会把第一个绑定的连接关掉——mid-turn 断连。
图 4 · Spawn tree 时间线(d1,4 个 agent,48m56s):并行/串行执行一目了然;底部快捷键支持 move / kill / pause / sort / filter——子代理集群的观测面。
3. stint:planner/builder/verifier 三角色轮次
stint 是 mode: stint playbook 驱动的多轮多角色执行层(4136 行):
- 角色 =
.stint/<role>.mdguard 文件,frontmatter 定义 order / session(fresh|continue) / enforce(read/write: soft|hard) / owns / appends / reads / artifacts / tasks;默认三角色 planner → builder → verifier(roster.py:83-86); - 轮次推进靠
JOURNAL.md:append-only,每 round 一个 section、每 role 一个子节;prompt 只带最近JOURNAL_ROUNDS_IN_PROMPT=2轮、MAX_JOURNAL_CHARS=16000截断(journal.py:25-26); - 状态 = backlog 状态机(add/assign/defer/reject/block/unblock/implement/proven/not_proven/reopen/drop,by 角色 → from → to)+ checks.json 台账 +
~/.raven/stints/<id>.json(heartbeat 60s / STALE 300s / claim PID+host); - 写权限是文件级的:ownership.py 的 owns/appends/never 三级 + glob 展开;enforce.py 越界写直接 undo(quarantine 副本先存),appends 带删行→trimmed 恢复——跑完才执法,跑中不拦。
4. 三个 harness 缺口(源码里挖出来的,不是文档写的)
- paused/interrupted/adrift 只持久化不驱动。stint 没有 owner 概念:ingest 只按 recency 把 stint 分 active/resumable/stale,
paused的 resume 只出 payload 由人判断;op cleanup-all/flush/requeue只是运行参数名,不是状态迁移。 - stint_round 不 fork。role 引用是 pinned 的;dry_run 只返 ref 不进 subagent;续跑=全量重传快照(对比主 agent 的 ACP resume/fork 能力)。
- unlock 六途径只记录不改状态机(CLI
_collect_responses:271-618 → :618-812)——人工放行是叙事性的,不改变 backlog 机。
类 actor turn 的差异:owner_type=stint 时 ship 能力受上限约束(dispatcher/stint_tool.py:1095-1103),parcel 寻址只认 direct parent zones(_DIRECT_PARENT_ARTIFACTS :4041-4080、resolvable_zones :4269-4280);out-of-scope 引用经 TurnExecutor._ancestor_cache 显式报错——“绝不静默 no-op”(:368-378)。
图 5 · 轮次推进实况:「切题技能 v1」2/3 节点已完成(crop_module 裁剪模块自测 → bridge_branch 切题指令分支),integrate_test 重启联调并端到端验证收尾中;v1 计划逐条汇报,与会话树里的 dag 记录一一对应。
四、ACP 协议栈双端全解
ACP(Agent Client Protocol)是 Raven 与外部 coding agent 之间的 stdio JSON-RPC 协议,双端合计 13.4K 行。这是整个系统里外交精度最高的部分——所有”能力声明-实际行为”的缝隙都在这里显式处理。
1. 服务端:Raven 作为 ACP server 被 IDE 驱动
- capabilities(acp/capabilities.py:43-101):
loadSession: True只因 replay 存在才声明——注释直白标注 false promise 风险;mcpCapabilities http/sse 均 False(子代理全走 stdio stanza 指向宿主端点);prompt 侧 image: True / audio: False;initialize_result容错构造:坏 protocolVersion 读意图不失败,authMethods: []= 无需认证。 - modes(acp/modes.py:34-79):mode 是会话状态非转写状态,不持久化,重开会话回连接默认。
- replay(acp/replay.py):session/load 不是 getter——把会话以 session/update 通知重放后才返回(客户端无需第二渲染器);notice/turn_ended 不作为助手语音重放;滚动累计 500 条 / 16KB 上限;只有重放里的 tool_call 是 pending 状态——重放时工作进行完毕,follow-up 带结果。
- questions(acp/questions.py:77-397)双路由:elicitation/create(正配,唯一能承载清单外答案)否则 session/request_permission(合成 tool call);无 elicitation 声明的自由文本问题无法回答→作为普通 agent message 上线并回落默认;HUMAN_ANSWER_TIMEOUT_S=900。
2. 客户端:Raven 驱动外部 coding agent(编排的真正前线)
pool(client.py):一连接 = 一子进程 + 读循环 + 请求相关。三个关键决策:
- launch 时
start_new_session=True且 pgid 在 spawn 时捕获后永不重推导——回收 pid 再 killpg 会杀错进程(:151-208); alive三重判活——npx 包装器会 park 在死子进程上:pid 活、stdout 关、不答话(:285-296);- binding 与 entry env 分离(见第 3 篇 §2-5),pool 会因 launch key 变化错误关闭首个连接。
prompt 发送(acp_agent.py:1537-1554 逐字):session/prompt + _meta.raven.usage + 附件作 resource links + cancel_session 绑定 + asyncio.shield(取消调用方不能取消底层 future,否则分不清真实 settle)。
回流传译 _TurnCollector(:199-830):agent_message_chunk 合并、tool_call 开合对(有的 agent 会重发)、plan 只有开帧断消息(改 4 次不会把叙述切成 4 段)、live republish 到 activity(transcript/tool_calls 实时上报);文件账目靠调用出现时拍基线——settle 时拍会把创建的文件说成一直都在;failed 调用的 diff 块丢弃(磁盘说了算)。
resume 决策(:1360-1376):is_stateful 读手快照的 loadSession 而非 resume 字段——实测多个 agent 都报 resume:false + loadSession:true 且都能正确 resume;session/load 期间挂丢弃 sink,否则重放的历史会被 unprompted recorder 记成无人值守工作。
3. 方言层:只认 agentInfo.name
只两个 dialect(claude-agent-acp / codex-acp),从 agentInfo.name 选而非 config(改名/双入口都正确);spec 方言是诚实默认。claude 方言三处偏离:_meta.claudeCode.toolName 真名、rawOutput+content 双发(```console 围栏原文泄漏到叙述)、TodoWrite/Task 不发 tool_call 只进 plan 帧——每个偏离都标了测量版本号(0.66.0/0.79.0/0.81.1)。
4. 权限应答:本轮解剖最重要的单个决策
无人值守场景只有”永远批准”或”永远拒绝”两种答案,Raven 选批准(permissions.py:1-34)。理由链:
- 实测 codex-acp 把任何错误(含 method-not-found)转成
{decision: cancel}整回合取消——选”拒绝”的后果是已流出的两句变 partial reply 无声失败; - 按 kind 选 option 不按 optionId——id 是 agent 私有词汇;
- 批准止于宿主自己的拒绝规则——放行越过操作员拒过的命令 = 把子代理升级。
配套纪律:一切客户端故障都映射成拒绝(RequestFailedError→client-error、ConnectionClosedError→connection-closed、TimeoutError→timeout、CancelledError→cancelled-turn 后重抛、catch-all→transport-error)——否则 OSError 会逃进 ToolRegistry.execute 被报成工具失败而非拒绝。
5. 两条隐形管道
- journal(journal.py:287 行):四类流量此前完全不可见——子代理被批准了什么、raven 出站帧、无主的迟到通知、stderr。文件先 0600 再写首字节(”帧里有全 prompt+全工具结果,world-readable 窗口根本不该存在”);MCP secret 在 journal-safe copy 里
<redacted>;64MB/7 天 reclaim。 - unprompted recorder:修 2026-08-26 “35 帧无人值守回合被当迟到 usage 丢弃”事故——用客户端已有的 message.start/token.delta/complete 三事件重放,客户端零改动;空回复回合记
[unprompted: N tool call(s), no message];idle 20s 兜底。
6. a2a:>2 agent 编排的真正入口
与 ACP 互补,a2a 管 agent 间互调(1537 行):三段拒绝门(gate.py:15-27)——not enabled(照单全收离线)/ not served(Unknown channel,agent 跳下一通道)/ path collision(换 route_path)。AAgentProxy 是本地 actor 的 A2A 化身(agent card 地址 :63-70、bearer auth :148-156、transfer :48-59);ChainedAgentExecutor 是 >2 agent 编排实际发生处——超过两个 agent 的链条不走 subagent DAG,走这里。
五、上下文工程三支柱与记忆演化
1. Curator:每回合一次的上下文裁缝
触发判据(context_engine/segments/curator.py:192-204):每回合 history_tokens = sum(item.tokens for item in manifest),低于 budget.available_history * fast_path_threshold 走 fast 直通,否则进有界 LLM 循环(curator.py:258-351,max_steps=12,temperature=0.1,模型 = context.curator_model 钉住或会话模型)。
Curator 手里 8 个工具:archive / retrieve / relevance / working-state / read-memory / build-plan——它不是 summarizer,是检索-规划器:慢路径产出的归档 JSONL 落 ~/.raven/workspace/memory/.curator/archive/YYYY-MM-DD/*.jsonl,working_state 以 # Curator Working State ... 附加在 system 尾部;失败回落是确定性计划(protected + relevance top-12 + recent 16,curator.py:466-481)。
与 loop 压缩的解耦:trimmer(history_trimmer.py:292-368)与 window.shrink 是两套 make-fit 机制,经 available_history 算术(curator 慢路径预算 ×0.60)保持出热路径——这是接缝处最容易被改错的地方。
2. token_wise:四断点的前缀稳定学
支柱 3 的全貌在 core/token_wise_stack.py:96-150 + cache_optimizer.py:136-200:
| 断点 | 内容 | 依据 |
|---|---|---|
| bp1 | 最后一个工具 schema | 工具清单是 prompt-cache 前缀首项 |
| bp2 | system 消息稳定头 | split_stable_prefix(content, int(m.get(STABLE_PREFIX_KEY) or 0))——只有 breakpoint 之前的 system 进缓存(记忆召回+router hits+Curator working state 随当前 user 消息派生,不缓存) |
| bp3-4 | 滚动尾(最近 3 条) | Hermes 的 system+3 复刻,A/B 对照实现同包 |
配置:cache_ttl 5m/1h → prompt_cache.set_ttl();max_breakpoints=floor 1(厂商拒收第 5 个断点——Anthropic 上限 4);非缓存模型 no-op 且深拷贝不改入参。深拷贝这条是必须的:同一 messages 对象在诊断快照和实际发送间共享,原地改断点标记会污染观测数据。
UsageTracker 是纯记录器:JSONL 追加 ~/.raven/telemetry/usage-YYYY-MM-DD.jsonl(schema_version 2,RAVEN_HOME 可迁移);record_delegated_usage 把子代理账单挂 delegation root;无价模型进 *_missing_calls 不清零(账不平比没账好);pricing 显式估价——Anthropic cache-read 10%、cache-write 125%/2.0× 按 TTL——计划计费/离线拒价,绝不糊一个估值糊弄账单。
3. 记忆引擎:纯 Markdown,克制得不像 2026 年
MemoryStore(consolidator.py:608-660)的全部家当:
1 | ~/.raven/workspace/user_memory/profile/user.md # 用户画像(+ .lock) |
无 sqlite、无向量库。写入=annotate(forced-tool LLM 通道,consolidator.py:985-1183);读取=get_memory_context 词法 H2 选取(:916);合并=refresh_section 的 LLM compare-and-set(:1305-1546)。工程判断:这个量级(单用户 MB 级)下 Markdown 的 diff/审阅/手工编辑价值远超向量检索的收益——检索精度由 everos 的 LanceDB 补位(第 8 篇),分工干净。
4. 技能演化:闭环在 everos,raven 只留了管道
第四支柱”Skill Self-Evolution”的分布:
- raven 侧(memory_engine/skill_forge):只是检索+反馈管道——
skill_forge/backend_source.py:1-87重包 RouterHit 进 prompt,organ_glue.py:260-309发 skill_usage 信号; config/raven.py:820-828明说 evolution 归 everos,auto_detect/auto_evolve/retirement 是占位(:1054-1069 默认全关);- 真正的 Detect→Draft→Active→Evolve→Retire 循环在 everos:
AgentCaseExtracted → trigger_skill_clustering(LLM 判 merge/mint)→ SkillClusterUpdated → extract_agent_skill(md-first,≤10 全入 prompt,sanitize_skill_name 防路径注入)→ cascade 投影(md→LSN→LanceDB)→ recall(BM25+dense 双轨); - 两个断点:feedback 是确定性 no-op(无 HTTP 端点、confidence 无 service 写路径,”反馈→置信度→演化”目前是断的);retire 未实现、退化为低 confidence——技能只增不汰。
死配置警告:relevance_decay=0.95 / relevance_reference_boost=0.15(raven/config/raven.py:103-107)零 reader——build_manifest 后 relevance 不可变,改这两个数字没有任何效果。
六、主动性引擎的双面孔
Raven 的主动性有两副面孔:cron 是真正在跑的实干家,Sentinel 是设计完备但本机关闭的规划师。分开解剖。
1. cron:jobs.json 持久化与重启语义
存储(config/paths.py:24-26 + cron_stack.py:475-482):
1 | { |
并发与执行:portalocker 文件锁(jobs.json.lock)+ PID claim TTL(30min)+ channel 分区(allowed_channels,不同渠道可并行);process-then-wait 主循环(最大睡眠 30s);锁内 claim、锁外执行、同一进程内串行(for job in my_jobs)。
重启语义(这部分设计意图最明确):
- recurring 任务跳过不 backfill;
- past-due one-shot “at” 被丢弃——注释对齐 iOS/Slack/Calendar 的行为(补发一次凌晨的闹钟没有意义),记入
last_startup_drops经 RPC 广播给页面; - 除非
fire_missed:重锚 now 立即触发一次; - 丢失的:SystemEventQueue(纯内存 max20 FIFO)、WakeScheduler 的排队原因、notified 集合——进程级状态全部归零。
2. 反 runaway 三道闸
silent_fire_limit=12:连续 12 次静默触发(无用户交互)后任务自动停(service.py:600-636 + cron_stack.py:280-311);notify_user_active仅 Origin.USER 重置:机器自己造的交互不算”用户在”(service.py:638-662);- event_wake 限流 300s(schema.py:719-733,WakeScheduler 合并同类唤醒);add_job 五层去重(service.py:711-924)——同消息同目标的重复任务根本进不了队列。
3. Sentinel:设计完备的规划师,本机关闭
无 sentinel 配置块 → SentinelConfig.enabled=False(config/raven.py:295)→ build_sentinel_stack 返回 None(proactive_stack.py:210-211)。若开启,运作方式是:tick 循环(默认 1800s)+ trigger 轮询(2s)+ DeferManager;每 tick 装配上下文(无 LLM 的 assembler)→ 刷新记忆态 → 到时计划位(±20min 窗口)→ 快路径(安静时段/未变上下文 TTL 3600s,不用 LLM)→ planner 决策(LLM)→ _route。
四条执行路径:
| 路径 | 行为 |
|---|---|
| nudge | DeliveryHub 非回合路径直投(_sentinel_origin=True,永不再入 agent loop,dispatcher.py:1-14) |
| nudge_inject | 入队在下一回合附加(injector.py:143-148) |
| nudge_defer | 等目标 idle 超阈值再走 dispatcher |
| spawn_agent | 走 SubagentManager.spawn,结果以 SUBAGENT origin 回 spine |
NudgePolicy 反垃圾数值(trigger_policy/policy.py):max/h=3、max/d=10(硬顶,高优先级也不过)、min_interval 300s、dismiss_cooldown 1800s、ignore_window 21600s、dedup_window 86400s、weekend multiplier 0.5;检查顺序 = quiet hours → day quota → hour quota(adaptive+weekend)→ L5 拒绝冷却(加权拒绝≥3 进冷却)→ L3 主题接受 → L7 周末 cap → topic quota;topic 规范化(_CANONICAL_SUFFIXES);_tuner 每小时按接受率调 hour multiplier。
4. 边界铁律
- 所有 origin 汇入同一
Scheduler.submit(spine/scheduler.py:571)——主动性和交互不分家,只分池与旁路; - 主动性器官不是 runtime 成员:cron/heartbeat/sentinel/wake 是进程级服务,在
rpc/bootstrap.py:313-360组装——generation 热切换不重启它们,这正是 cron 任务跨 reload 存活的原因; - 非 USER origin 的打断语义降级(INTERRUPT/INJECT→APPEND),消息续跑循环跳过(turn_path.py:3106-3116);
- 外部 vs 内部:healthcheck 是 systemd timer 跑 shell 写
~/.raven/healthcheck.last_alert——Raven 代码不参与,这是”系统外保健医生”与”系统内心跳”的分层。
七、执行面的牙齿——工具、权限、MCP 与沙箱真相
1. 工具注册与分发:顺序即安全
ToolRegistry.admit_tool(registry.py:64-117)注册期校验(ToolAdmissionError 在注册期抛而非回合内);schema 是 OpenAI function 格式且 copy.deepcopy(parameters)——防工具把 live parameters 泄露给模型。
execute() 的顺序(registry.py:821-1044)每一环都是有意为之:
1 | 可见性(turn_scope 快照)→ 截断护栏(截断调用不执行)→ JSON 修复 → 参数校验 |
两个要点:权限闸门故意放在超时上限之前——人做的决策不该被 timer 杀;错误回喂只对 retryable 附 hint,本层无重试——重试是模型侧决策。
turn_scope 快照是 MCP 竞速的根因:token = self._turn_names.set(dict(self._tools)) 在回合入口处冻结(registry.py:664,loop 调用点 main.py:868-870)。MCP 异步连接(~1.2s)完成时 CLI one-shot 进程往往已退出,下一回合才可见——所以 CLI 冒烟调 MCP 必报 tool 'mcp_xxx' is not available(官方措辞 “available from a later turn”),而飞书真实路径(常驻 gateway runtime)无此问题。这是 by-design,不是 bug——冒烟验证 MCP 必须走真实消息路径。
wrapper 的 inputSchema 服务端原文透传(mcp/client.py:40)——MCP server 完全控制模型看到的 schema,接第三方 server 时这条就是信任边界。命名空间 mcp_<server>_<tool>,冲突/超长加 12 位 SHA1 后缀;握手看门狗 90s;OAuth 可停车;streamableHttp 自建 httpx client(follow_redirects=False,timeout=None);日志 MCP server '{}': connected, {} tools registered"(manager.py:811)就是运维判定成功的锚点。
合并注:原文本篇在「1. 工具注册与分发」与「3. 权限瀑布」之间还有独立的第 2 节(MCP 连接与信任边界方向),其标题与引导句在网页抓取时被正文摘要器略去未返回;上文第 1 节末段已保留该节可获取的实质要点(inputSchema 服务端原文透传、命名空间与 SHA1 后缀、握手看门狗 90s、OAuth 可停车、streamableHttp 自建 httpx client、日志锚点 manager.py:811)。本地母本《01-主报告-核心逻辑全解剖.md》§12 对同一点的记载为:”MCP:wrapper 的 inputSchema 服务端原文透传(MCP server 完全控制模型看到的 schema);命名空间
mcp_<server>_<tool>(冲突/超长加 12 位 SHA1);握手看门狗 90s;OAuth 可停车;日志 ‘MCP server '{}': connected, {} tools registered’(manager.py:811)即运维手册判定成功的锚点。”另母本同节载有插件信任模型一条(本篇第 1 节 execute() 顺序中”插件 tool_gates”一环即其落点):插件为进程内任意受信任 Python、无沙箱,发现期不 import(除 entry-point 分支),tool_gates 可否掉工具调用但碰不到权限闸门(plugins/manifest.py;registry.py:1046-1067)。
3. 权限瀑布(permissions/gate.py:126-224)
1 | mode 解析 → builtin ruling → user DENY → user ALLAY → default tier |
配套纪律:
- builtin.py 硬 deny 模式(
mkfs、dd if=、>/dev/sd、fork bomb)压过一切用户 allow(gate.py:5-13); ALLOW_ALWAYS只持久化 exec 类规则(_persist :391-419);- turn digest 去重——同回合同命令不二次打扰;
allow_ask=False或无 responder → refuse(源=UNATTENDED,源=UNATTENDED,fail-closed);- ACP 侧同一审批往返的第二传输:一切客户端故障都拒绝——宁可拒掉一百次合法请求,也不放一次来源不明的(permissions.py:169-202 的 catch-all 注释原话逻辑)。
瀑布里唯一面向用户的一跳,实况长这样:
图 6 · ask_user 实况:Raven 跑完一轮自动排查(pendingCrop 复查核查)后把决策权交还用户——「锚点切分必须靠号锚点升级,怎么走?」带 1-4 快选、7 分钟倒计时、可追加备注;选 1 先零改动验证再接线,成了立刻接线。无人值守时,这一跳就是 fail-closed 的拒。
4. SSRF 与密钥卫生
security/network.py:judge_url_target逐跳检查(scheme、私网字面量、全 DNS 解析)、_pin_request防 DNS rebinding、guarded_fetch禁 follow_redirects;调用方 web_fetch/media_gen。redact.py15 类密钥模式覆盖全部客户端负载(acp/updates、acp/replay 等 4 处调用,自述 defence-in-depth)。trust.py的wrap_untrusted只是提示词级包裹——无强制力,别把它当安全边界。
5. 沙箱实况:默认无隔离
这是全篇最需要知道的一条:
- 默认 backend
none→DirectExecutor= 宿主机普通子进程(sh -c);deny-list 仅在not sandboxed时生效(shell.py:270-273); interfaces.py的is_sandboxed默认 True 是失败安全方向——但反直觉的是它会让 deny-list 失效:未覆写的第三方执行器申报自己已沙箱化,宿主 deny-list 就跳过了。审第三方执行器时的暗礁;- Boxlite 是唯一真隔离(microVM,需 Apple Silicon/KVM,本机未装;
allow_net默认开放); - 全包无 bubblewrap / unshare / seccomp / cgroup。
6. RPC 控制面(36.6K 行择要)
- server.py:JSON-RPC 2.0 换行帧过 TCP-loopback;token 首行 10s 超时(恢复”只有我们 spawn 的孩子能说话”边界);1MiB 帧上限;逐帧 create_task 并发;写锁 + drain 背压。connect_accepted_socket 不用 pipe transport——双向 socket 任何入站字节会触发 reader callback 关闭,send_frame 全静默 no-op(/cha autocomplete 连丢 5 帧的肇事机制,:120-136)。
- dispatcher.py:自写几十行的理由很实际——pydantic v2 覆盖已够、少依赖=小 pip-audit 面;SystemExit 拦成 internal_error。
- 方法表(methods/init.py:114-246):~30 组按序注册,顺序即事实(真 handler 必须在 stub 后注册,重名 raise 而非 last-wins);测试 + openrpc.json 钉名。
- live_probe(161 行):所有外部通道唯一出口;从 lock payload 拿端点+token(token 是 WS 首帧);失败答 None → 渲染 “unknown” 不渲染 “disconnected”——探测失败和真断开是两回事。
- reload.mcp:廉价 gate 在确认前(没变直接 noop);”reconciled” 不叫 “reconnected”——计数含 detach/失败,叫 reconnect 会把全断报成功。
- teardown 顺序(bootstrap.py:401-479)= 全系统最纪律的一段:cancel brokers → cron stop → begin_drain + subagents.cancel_all(子代理必须先行——跑完的 announce 进已封 submit 只剩取消)→ turn_teardown → plugin services → drain backend stores(先 drain 后 stop)→ close MCP → browser close(Chromium 持久 profile 锁)→ close_pool(不收 terminal 信号的孤儿)。
7. providers / routing / config
- provider 抽象(providers/base.py):
chat_with_retry/chat_stream统一入口;parse_llm_error输出类别+端点(正常见第 2 篇失败面);tool_names 的 sanitary_form 做命名空间净化。 - routing 是”run 时选实现”(routing.pick)——配置是意图、代码是裁决;实际模型以 config.json 为准(读文档不如读 config,本轮就撞上手册写 glm-5.3-flash 而实际已切 step-5-preview 的实例)。
- config 顶层键:a2a / agents / channels / language / memory / permissions / providers / subagents / plugins / tools / embedding;渠道配置走 dispense 制(声明键与 socket 字段分离,门禁式准入);24 小时内 6 次 config.json.bak + migrations.json——配置迁移是受支持路径,这段仍在活跃演化。
八、第二服务 everos 与观测层 trajectory
1. everos:被误认作”子包”的独立王国
先纠个架构错觉:很多人(包括初版的运维手册)以为 everos 是 raven 的子包。实际上它是顶层独立包 everos/(v1.4.1,49131 行)+ raven 侧桥接插件 raven_everos/(everos-memory,7006 行)。运行实况:everos server 是 raven gateway 的子进程(PPID=424),监听 127.0.0.1:18791 纯 HTTP REST,无鉴权、靠只绑环回保命。
启动链(raven_everos/server.py):ensure_everos_server(:1057)→ 健康探测(/health + 空 POST /api/v2/memory/search 防”假健康”——只 ping /health 会相信一个装死的服务,:97-115)→ 端口写 everos.toml [api] 后回读校验(:823-853)→ Popen(:961-1043 跨进程 file_lock spawn)→ 日志落 ~/.raven/logs/everos-server.log。everos 侧 uvicorn create_app 双挂 /api/v1 legacy 与 /api/v2 canonical。
存储三层(实测 ~/.raven/everos 53MB):
| 层 | 内容 | 角色 |
|---|---|---|
| Markdown | 21 个物化 SKILL.md(frontmatter: id/confidence/source_case_ids/cluster_id) | source of truth |
| SQLite(23MB) | md_change_state LSN 队列、cluster 24 行 / cluster_member 194 行 | 队列与集群 |
| LanceDB(7 表) | 投影(60s optimize / 300s prune / 12h rebuild,quiesce 冻结保只读) | 检索 |
无 git、无 jsonl。纯 HTTP REST 边界——raven 只发消息+检索,算法全在 everos。
skill 自演化闭环(第 5 篇 §4 的运行态细节):
1 | AgentCaseExtracted |
两个断点(第 5 篇预告过,这里给证据):feedback 是确定性 no-op(backend.py:1557-1588——everos 无 HTTP 消费端点、confidence 无 service 写路径,raven 发的 skill_usage 信号被丢,”反馈→置信度→演化”闭环是断的);retire 未实现、退化为低 confidence——技能只增不汰。
2. trajectory:没有 daemon 的纯 CLI 轨迹栈
第二轮架构纠偏:传闻中 trajectory 有个 30 行 JSON-RPC daemon、recover.py、CLI goto N/seek 恢复——全部不存在(rpc/methods/ 对 trajectory 零命中)。7446 行 / 15 模块的真实全貌:conversation 821(读侧重建)、redact 627、bugreport 1143、store 713、replay 1204、regression 842、review 505、cassette 359、sanitize 341、report 67、verdict 146、bundle 261、completeness 243、errors 24。轨迹层无网络服务,纯 CLI 面对面。
写入侧:span 日志与三层吞异常
事实记录由 raven/tracing/ 写(agent/loop/_shared.py:78、tools/registry.py:19、subagent/manager.py:61 等经 from raven.tracing import trace 装饰器):audit.span.v1 schema(spans.py:build_span :66-125:traceId/spanId/parentSpanId/name/status.code/attributes/events;attempt.id 是保留键被静默 drop)。
追加失败闭环是全系统最值得抄的一段——三层降级:
1 | trace.py:span() :243-248 ERROR 标记后原样重抛宿主异常(tracing 不改宿主语义) |
enabled()=False 时整个 span() 直接 yield no-op(零 I/O),replay 场景可经 ContextVar 级静默。内容寻址:sha1 只用于 blob 命名与自愈(_blobs/<sha1[:2]>/<sha1>.<ext>,_blob_is_intact 缓存 inode+mtime+size 后全文件重算,不符则 _repair_blob 用 os.replace 指回——“审计 trail 不二次撒谎”)。
seal 轮换触发条件(tracing/store.py:_rotate_if_needed :103-118):A=活动日志 mtime 的 UTC 日≠今天(跨日封);B=待写后大小 > max_bytes(默认 50MB,env 可调)。归档成 archive/<day>/audit-spans-<day>-<HHMMSSffffff>.log。实测吻合:零点后跨日封、活动段 2MB 在写。
事务侧:pin 永不 purge
trajectory/store.py(713 行)= pin 注册表 + attempts.json + rotation 透明读:
- 保留契约(:3-15):
pinned ids 永不 purge,purge 工具必须查is_pinned(:582-602); - `merge/split 永远 over-protect:split 时锁内先把定义/别名的 pin 下沉到每个成员再删定义(:502-512)——崩溃或并发交错都只会留冗余保护,不会丢保护;merge 提交失败 compare-and-delete 回滚(:436-448);
- 读侧:
span_log_paths(:649-655)= archive 旧→新 + active 的写序,iter_spans逐行容错(UnicodeDecodeError/JSONDecodeError 跳行,”一条坏行不掩埋整条轨迹”)。
运维面真实映射
| 传闻 | 实物 |
|---|---|
| 最小 JSON-RPC daemon | ReplayState 原语面(llm_cursor/tool_cursor 双游标,replay.py:204-227),seek/next/verbose 是进程内等价物 |
| replay 从 seek 恢复/断线 | seek 真实语义=历史裁剪 _history_cut(:984-1030,时间优先+内容确认);断线=三类 fatal divergence:exhausted / missing output / corrupt recording(574-629) |
| recover 四命令 | bugreport.py 生命周期(:944/1005/1022/1093):draft=进程被杀读时原子转 failed;冻结先行(确认前 snapshot/export 冻结);24h stale staging 清理 |
| seal/upgrade 重操作 | seal heavy≈pin never-purge;upgrade heavy≈attempts.json merge/split 迁移(与二进制升级无关) |
| browse 在包内 | 在 CLI 不在包内;regression 是静态提交门禁(schema + artifact 路径逃逸检查 + 全 token sha256 人工审 + 256KiB/1MiB 预算) |
CLI 退出码 0/1/2(replay),所有 id-taking 命令先 trace id→attempt id 解析,Rich 渲染全过 escape。
3. 系列收束:三句话
- Raven 的骨架是”一套总线、五种 origin、六个横切层”——稳定到可以逐层拆下线;
- 它的肌肉在接缝处——两套 make-fit 机制的解耦、launch_cwd/session_cwd 的分离、turn_scope 快照与 MCP 异步的竞速、teardown 的子代理优先——全部长在注释里;
- 它的边界同样诚实——feedback no-op、retire 缺失、Sentinel 关闭、sandbox 无隔离、eval unwired:知道哪些管子没接线,比会画架构图更重要。
(完)
原始署名与版权
- 作者:林浩(博客:林浩的数字空间,https://bloodysky.top/ )
- 原发布时间:2026-10-01(8 篇同日发布;第 8 篇为系列完)
- 许可协议:CC BY-NC-SA 4.0(https://creativecommons.org/licenses/by-nc-sa/4.0/ )——本博客所有文章除特别声明外,均采用该许可协议。转载请注明来源 林浩的数字空间。
- 站点变更说明(2026-10-02):原 8 篇原文已从本站删除、合并为本文;下方原文链接仅作历史记录保留,页面已不再提供访问。
- 原文链接:
- 架构总览与工程美学 — https://bloodysky.top/2026/10/01/2026-10-01-raven-anatomy-overview/
- 一条飞书消息的完整旅程 — https://bloodysky.top/2026/10/01/2026-10-01-raven-message-journey/
- Subagent 编排层与 stint 轮次 — https://bloodysky.top/2026/10/01/2026-10-01-raven-subagent-orchestration/
- ACP 协议栈双端全解 — https://bloodysky.top/2026/10/01/2026-10-01-raven-acp-protocol/
- 上下文工程三支柱与记忆演化 — https://bloodysky.top/2026/10/01/2026-10-01-raven-context-memory/
- 主动性引擎的双面孔 — https://bloodysky.top/2026/10/01/2026-10-01-raven-proactivity/
- 执行面的牙齿——工具、权限、MCP 与沙箱真相 — https://bloodysky.top/2026/10/01/2026-10-01-raven-security-toolchain/
- 第二服务 everos 与观测层 trajectory — https://bloodysky.top/2026/10/01/2026-10-01-raven-everos-trajectory/
- 合并说明:本文由上述 8 篇原文忠实合并而成,正文未作删减或缩写;仅去除每篇重复的系列导航、站点页头页脚与重复的引言/作者介绍,并将各篇原有小节结构保留为章内
###小节。原文中的代码块渲染编号(如 “1 2 3” 行号)已按纯代码块清理,文字内容不变。






