Appearance
Shadow Harness 从哪些边界开始:Architecture、Domain Model 与 Model Adapter
前置:Model、Tool、Context、Runtime、Reliability、Persistence、Service Runtime、Security、Observability 与 Deployment 基础;已有 failure tests
核心问题:Shadow Harness 的最小 Domain/Adapter 边界应该怎样切,才能替换 Model Provider 而不改 Runtime 主循环?
用户请求进入 API 后创建 Run,ContextManager 组装 ModelRequest,模型提出 Tool Call,Runtime 验证/执行并持久化,再进入下一 Turn。换 OpenAI→其他 provider 时 ToolCall domain 不变,仅 adapter 转换。
Mental Model
text
API/User → Runtime → Context/Model/Tools/Planner/State → Observability/Eval → API/Event Stream/ConsoleDeveloper Console 只是这些真实 backend facts 的可视化出口;如果底层没有统一 Run/Node/Tool/Trace/Checkpoint contract,前端无法补救架构混乱。
Architecture Overview
总体架构以 domain contract 为中心:Run/Node/Tool/Context/Trace 等内部类型稳定,provider、DB、MCP、sandbox 作为 adapter。
总体架构要明确 Model、Context、Retriever、Tools、Planner、Runtime、State、Trace/Eval、Workspace/API 的依赖方向和数据流。核心原则是模型建议、程序持有执行事实。
Domain Model
Domain Model 定义 Run、Node、ToolCall、Checkpoint、Approval、Trace 等稳定业务概念及 invariant。它不是 ORM/JSON schema 的镜像,而是 Harness 对世界的内部语言。
Model Adapter
Module 02 已定义模型层 contract。最终 Harness 只让 ModelAdapter 做 anti-corruption mapping:domain ModelRequest/Response/Event/Error/Usage ↔ provider SDK/API;Runtime、Planner、Store 不看到 provider object。
capability detection 与 provider version 进入 RunManifest;
最小实现 / 数据结构
text
request → api → run_state → context → model/planner
↓
graph/scheduler
↙ tool retrieval ↘
workspace mcp
↓
checkpoint + trace + eval从一个 API 请求走完整条主链
用户提交:修复 auth bug 并运行测试。在 Shadow Harness 中,一次最小执行可以穿过:
text
POST /runs
↓
RunService 创建 RunState
↓
ContextManager 组装 instructions + workspace facts
↓
ModelAdapter → ModelDecision(tool calls / final)
↓
ToolRegistry + ToolExecutor
↓
Runtime 提交 Observation / NodeState
↓
CheckpointStore
↓
Event/Trace 输出给 Developer Console这里 Domain Model 的作用是让核心层说自己的语言:RunId、ToolCall、ToolResult、Checkpoint、ApprovalRequest。Provider SDK 的 response object、MCP SDK object、FastAPI request 都应该在 Adapter 边界被转换掉,否则核心 Runtime 会同时依赖所有外部框架。
因此架构判断可以用一个简单问题检查:如果明天更换 Model Provider、HTTP 框架或 MCP SDK,RunStateMachine 是否需要跟着改? 如果答案是“需要大改”,说明 Adapter/Domain boundary 还不够干净。
🔍 源码对照:真实工程把 Turn Context / Observation / Settlement 拆成不同 owner
完整源码与通用分析见 09-01 Run Lifecycle / State Machine。这里不重复代码;这里关注架构 owner:Turn Context、Observation、Settlement 应拥有不同生命周期,避免把 Provider Session、Workspace 与 durable state 塞进单一巨型对象。
源码说明
这个仓库最适合作为 Architecture Boundary 对照,而不是代码模板:Host/Runner 管 agent execution,Coordinator 管 provider/relay 等边界,exec daemon 再把具体执行环境隔离出去。它证明复杂 Harness 往往需要把“模型接口、运行控制、执行能力、外部协议”拆层,而不是一个 Agent class 包办所有事情。
工程边界
Shadow Harness 不需要 Electron、renderer 或同样的进程拓扑。我们提炼 domain boundary 后,应选最小部署形状,只有在隔离/扩缩/故障域确有收益时才拆进程。
Shadow Harness 对照
- Domain Model 不依赖 OpenAI/MCP/Docker SDK 类型。
- Adapter 只在边缘翻译 provider/protocol/execution environment。
验证
用 FakeModel + in-process FakeTool 跑完整 Runtime,再替换真实 provider/MCP adapter;核心 RunState/Observation 类型不应改变。
关联源码
自测
- 为什么 Shadow Harness v0.1 应先稳定 Domain Model 与 Model Adapter,而不是一开始把 Queue、DB、MCP 全接上?
- 替换 Provider 时如果 Runtime 也必须修改,说明哪条 adapter boundary 没建立好?