|
|
@@ -0,0 +1,1084 @@
|
|
|
+# VideoImageProductionBuild 可视化接入
|
|
|
+
|
|
|
+> 文档状态:接入设计稿
|
|
|
+> 当前项目协议:Production 0.7
|
|
|
+> 当前验证日期:2026-07-29
|
|
|
+> 观测台地址:<http://8.147.104.190:8931/>
|
|
|
+> 当前私有源最新 SDK:`obagent-sdk 0.5.2`
|
|
|
+
|
|
|
+## 1. 文档目标
|
|
|
+
|
|
|
+本文说明如何把 `obagent-sdk` 接入 VideoImageProductionBuild,使一次真实 Production
|
|
|
+运行可以在观测台中按 Run、Workflow、Agent、模型调用、工具调用和确定性代码阶段查看。
|
|
|
+
|
|
|
+本文覆盖:
|
|
|
+
|
|
|
+- 本地环境和依赖配置;
|
|
|
+- SDK 的主要接口能力;
|
|
|
+- 当前项目的模块边界与接入位置;
|
|
|
+- Production Graph、Segment Loop、恢复运行和 completed no-op 的表达方式;
|
|
|
+- 输入、输出、工具、媒体和血缘的申报约定;
|
|
|
+- 失败降级、隐私、安全和并发注意事项;
|
|
|
+- 分阶段实施与验收方案。
|
|
|
+
|
|
|
+本文是接入方案,不代表业务代码已经完成接入。当前项目环境已安装并验证
|
|
|
+`obagent-sdk 0.5.2`,但源码中尚未加入 `configure()`、`observe.run()` 或
|
|
|
+`observe.module()`。
|
|
|
+
|
|
|
+## 2. 两套“可视化”的职责边界
|
|
|
+
|
|
|
+当前项目会同时存在两套互补能力,不能互相替代。
|
|
|
+
|
|
|
+| 能力 | 数据来源 | 主要用途 | 是否业务事实 |
|
|
|
+|---|---|---|---|
|
|
|
+| 仓库内 `visualization/` | Run 目录、正式 JSON Contract、Journal、Artifact | 离线回放正式 Production 事实,查看 Plan、Segment、Artifact 和验收结果 | 是,以落盘合同为准 |
|
|
|
+| `obagent-sdk` 观测台 | 运行时主动上报、LangChain/LangGraph 自动采集 | 查看实时调用树、模型推理、工具调用、模块输入输出、耗时和 token | 是运行遥测,但不能代替正式合同 |
|
|
|
+
|
|
|
+必须遵守以下边界:
|
|
|
+
|
|
|
+1. 正式交付状态仍以 Production Contract、Checkpoint、Journal 和 Artifact 为准。
|
|
|
+2. obagent 上报失败不能让 Production 失败,也不能改变正式业务结论。
|
|
|
+3. 观测台不能根据“调用完成”自行推断 Segment PASS 或 Production COMPLETED。
|
|
|
+4. `CONTRACT_INVALID`、`OUTCOME_UNKNOWN`、未知副作用等正式语义必须原样上报,不能归并成普通失败或普通运行中。
|
|
|
+5. 不为“看起来完整”而制造不存在的模块执行、工具调用、轮次、Artifact 或成功结论。
|
|
|
+
|
|
|
+## 3. 已验证的运行环境
|
|
|
+
|
|
|
+当前项目环境:
|
|
|
+
|
|
|
+```text
|
|
|
+项目根目录 /Users/samlee/Documents/works/VideoImageProductionBuild
|
|
|
+Python 3.12.13
|
|
|
+虚拟环境 .venv
|
|
|
+SDK obagent-sdk 0.5.2
|
|
|
+服务端 obagent-server 0.1.0
|
|
|
+```
|
|
|
+
|
|
|
+已完成的连通性验证:
|
|
|
+
|
|
|
+- `pip index` 确认私有源最新版本为 `0.5.2`;
|
|
|
+- SDK `doctor` 通过;
|
|
|
+- `GET /api/health` 返回 HTTP 200;
|
|
|
+- 本机 `~/.obagent/wal` 无积压;
|
|
|
+- 测试 Run 已成功落库并在页面渲染;
|
|
|
+- 测试 Run 服务端 ID 为 `258`,客户端 UID 为 `dffee26724b64578`;
|
|
|
+- 页面显示 Run、模块定义、运行实例、输入槽、过程记录和结构化输出;
|
|
|
+- 浏览器控制台无 warning/error。
|
|
|
+
|
|
|
+## 4. 安装与版本管理
|
|
|
+
|
|
|
+### 4.1 安装到当前虚拟环境
|
|
|
+
|
|
|
+必须使用项目 `.venv` 的 Python,避免安装到系统 Python:
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /Users/samlee/Documents/works/VideoImageProductionBuild
|
|
|
+
|
|
|
+.venv/bin/python -m pip install -U obagent-sdk \
|
|
|
+ -i https://pypi.aiddit.com/repository/pypi-group/simple
|
|
|
+```
|
|
|
+
|
|
|
+确认版本:
|
|
|
+
|
|
|
+```bash
|
|
|
+.venv/bin/python -m pip show obagent-sdk
|
|
|
+
|
|
|
+.venv/bin/python -m pip index versions obagent-sdk \
|
|
|
+ -i https://pypi.aiddit.com/repository/pypi-group/simple
|
|
|
+```
|
|
|
+
|
|
|
+### 4.2 正式纳入项目依赖
|
|
|
+
|
|
|
+当前 SDK 只安装在本地 `.venv`,尚未写入 `pyproject.toml` 和锁文件。正式接入时应把
|
|
|
+SDK 纳入项目依赖并更新锁文件,建议先约束在兼容版本范围:
|
|
|
+
|
|
|
+当前仓库使用 PEP 621 的 `project.dependencies` 数组,建议加入:
|
|
|
+
|
|
|
+```toml
|
|
|
+dependencies = [
|
|
|
+ # ...现有依赖...
|
|
|
+ "obagent-sdk>=0.5.2,<0.6",
|
|
|
+]
|
|
|
+```
|
|
|
+
|
|
|
+不要只依赖某台机器上已存在的 `.venv`。CI、服务器和其他开发机必须能通过项目依赖声明复现。
|
|
|
+
|
|
|
+## 5. 环境配置
|
|
|
+
|
|
|
+### 5.1 建议的环境变量
|
|
|
+
|
|
|
+SDK 本身不会自动读取环境变量或 `.env`。以下变量是本项目适配层的约定,必须由项目代码读取后
|
|
|
+显式传给 `configure()`。
|
|
|
+
|
|
|
+```dotenv
|
|
|
+# 观测总开关。建议本地和测试环境先开启。
|
|
|
+OBAGENT_ENABLED=true
|
|
|
+
|
|
|
+# 当前已验证的观测台。
|
|
|
+OBAGENT_ENDPOINT=http://8.147.104.190:8931
|
|
|
+
|
|
|
+# 稳定项目标识。用于筛选和 module_key 前缀,不要随显示文案变化。
|
|
|
+OBAGENT_PROJECT=video_image_production_build
|
|
|
+
|
|
|
+# 观测台启用鉴权时填写;当前未配置时留空。
|
|
|
+OBAGENT_API_KEY=
|
|
|
+
|
|
|
+# 可选参数。
|
|
|
+OBAGENT_TIMEOUT=10
|
|
|
+OBAGENT_BATCH_SIZE=200
|
|
|
+OBAGENT_FLUSH_INTERVAL=0.5
|
|
|
+```
|
|
|
+
|
|
|
+推荐固定:
|
|
|
+
|
|
|
+```text
|
|
|
+project video_image_production_build
|
|
|
+project_name 视频图片制作闭环
|
|
|
+agent production_build
|
|
|
+```
|
|
|
+
|
|
|
+`project`、`agent` 和 `module_key` 是跨 Run 聚合的稳定身份,不应包含 thread ID、Plan
|
|
|
+版本、Segment ID 或时间戳。这些逐次变化的信息应放入 `meta`、`payload`、`branch_key`
|
|
|
+或输入槽。
|
|
|
+
|
|
|
+### 5.2 配置加载时机
|
|
|
+
|
|
|
+`run_production.py` 当前会在 `run_full_production()` 内调用:
|
|
|
+
|
|
|
+```python
|
|
|
+load_dotenv(PROJECT_ROOT / ".env", override=False)
|
|
|
+```
|
|
|
+
|
|
|
+因此 `configure()` 必须在这一步之后、第一次 `observe.run()` 之前调用。不要在模块 import
|
|
|
+阶段读取 `.env` 并配置 SDK,否则运行时 `.env` 还没有加载。
|
|
|
+
|
|
|
+建议未来增加集中适配器:
|
|
|
+
|
|
|
+```text
|
|
|
+production_build_agents/observability.py
|
|
|
+```
|
|
|
+
|
|
|
+适配器负责:
|
|
|
+
|
|
|
+- 读取和校验本项目的 `OBAGENT_*` 配置;
|
|
|
+- 调用一次 `configure()`;
|
|
|
+- 生成稳定的 Run 参数;
|
|
|
+- 把 Pydantic Model、Path、Enum 转成可上报 JSON;
|
|
|
+- 对敏感字段和超大字段做裁剪;
|
|
|
+- 提供不抛异常的辅助函数;
|
|
|
+- 提供客户端 UID 到服务端 Run ID 的只读查询。
|
|
|
+
|
|
|
+建议的配置函数:
|
|
|
+
|
|
|
+```python
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+import os
|
|
|
+
|
|
|
+from obagent_sdk import configure
|
|
|
+
|
|
|
+
|
|
|
+def configure_observability() -> None:
|
|
|
+ enabled = os.getenv("OBAGENT_ENABLED", "true").lower() in {
|
|
|
+ "1", "true", "yes", "on",
|
|
|
+ }
|
|
|
+ configure(
|
|
|
+ endpoint=os.getenv(
|
|
|
+ "OBAGENT_ENDPOINT",
|
|
|
+ "http://8.147.104.190:8931",
|
|
|
+ ),
|
|
|
+ api_key=os.getenv("OBAGENT_API_KEY", ""),
|
|
|
+ project=os.getenv(
|
|
|
+ "OBAGENT_PROJECT",
|
|
|
+ "video_image_production_build",
|
|
|
+ ),
|
|
|
+ timeout=float(os.getenv("OBAGENT_TIMEOUT", "10")),
|
|
|
+ batch_size=int(os.getenv("OBAGENT_BATCH_SIZE", "200")),
|
|
|
+ flush_interval=float(
|
|
|
+ os.getenv("OBAGENT_FLUSH_INTERVAL", "0.5")
|
|
|
+ ),
|
|
|
+ enabled=enabled,
|
|
|
+ )
|
|
|
+```
|
|
|
+
|
|
|
+配置解析错误应在启动时给出清晰提示;远端上报失败则必须降级,不得破坏业务运行。
|
|
|
+
|
|
|
+## 6. SDK 接口能力
|
|
|
+
|
|
|
+### 6.1 正确导入方式
|
|
|
+
|
|
|
+```python
|
|
|
+from obagent_sdk import configure, observe
|
|
|
+from obagent_sdk.observe import InputBlock
|
|
|
+from obagent_sdk.integrations.langgraph import graph_spec
|
|
|
+```
|
|
|
+
|
|
|
+也可以使用 `observe.InputBlock`。`InputBlock` 不能从 `obagent_sdk` 包顶层直接导入。
|
|
|
+
|
|
|
+### 6.2 `configure()`:进程级配置
|
|
|
+
|
|
|
+```python
|
|
|
+configure(
|
|
|
+ endpoint="http://8.147.104.190:8931",
|
|
|
+ project="video_image_production_build",
|
|
|
+ api_key="",
|
|
|
+ timeout=10.0,
|
|
|
+ batch_size=200,
|
|
|
+ flush_interval=0.5,
|
|
|
+ enabled=True,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+关键规则:
|
|
|
+
|
|
|
+- 必须在第一次 `observe.run()` 前调用;
|
|
|
+- SDK 不自动读取环境变量;
|
|
|
+- 没有 endpoint 时 SDK 会降级为空存储并告警,业务继续;
|
|
|
+- 一般一个进程只配置一次;
|
|
|
+- 上报失败的数据会进入本地 WAL,后续可重放。
|
|
|
+
|
|
|
+### 6.3 `observe.run()`:一次顶层业务运行
|
|
|
+
|
|
|
+```python
|
|
|
+with observe.run(
|
|
|
+ agent="production_build",
|
|
|
+ objective="完成指定 Global Data Delivery 的视频图片生产",
|
|
|
+ project="video_image_production_build",
|
|
|
+ project_name="视频图片制作闭环",
|
|
|
+ model_name="",
|
|
|
+ payload={...},
|
|
|
+ meta={
|
|
|
+ "run_name": "Production · <thread_id>",
|
|
|
+ "thread_id": "<thread_id>",
|
|
|
+ "protocol_version": "0.7",
|
|
|
+ "execution_mode": "fresh",
|
|
|
+ },
|
|
|
+ auto_collect=True,
|
|
|
+ round_anchor=None,
|
|
|
+) as run_handle:
|
|
|
+ result = run_production_graph(...)
|
|
|
+ run_handle.finish(
|
|
|
+ final_output=result,
|
|
|
+ ok=result.get("status") == "COMPLETED",
|
|
|
+ )
|
|
|
+```
|
|
|
+
|
|
|
+主要参数:
|
|
|
+
|
|
|
+| 参数 | 用途 |
|
|
|
+|---|---|
|
|
|
+| `agent` | 顶层业务 Agent 的稳定名称 |
|
|
|
+| `objective` | 本次运行目标 |
|
|
|
+| `project` | 项目标识;未传时使用 `configure(project=...)` |
|
|
|
+| `project_name` | 页面显示名 |
|
|
|
+| `model_name` | 主模型,用于成本归集 |
|
|
|
+| `payload` | 初始业务入参,原样 JSON 化保存 |
|
|
|
+| `meta` | thread ID、协议版本、环境、显示名等业务元数据 |
|
|
|
+| `auto_collect` | 是否自动采集当前上下文中的 LangChain 调用 |
|
|
|
+| `round_anchor` | 循环 Run 的轮次切分规则 |
|
|
|
+| `spec` | 外层 Workflow 结构定义 |
|
|
|
+
|
|
|
+`run_handle.run_id` 是 SDK 生成的客户端 UID,不是服务端数据库数字 ID。
|
|
|
+
|
|
|
+`run_handle.finish()` 可以提前声明最终产物;`with` 退出时 SDK 仍会幂等收尾并关闭上报线程。
|
|
|
+未捕获异常会继续向外抛,同时 Run 自动标记为 failed。
|
|
|
+
|
|
|
+### 6.4 `observe.module()`:业务模块边界
|
|
|
+
|
|
|
+```python
|
|
|
+with observe.module(
|
|
|
+ "segment_executor",
|
|
|
+ kind=observe.KIND_AGENT,
|
|
|
+ title="Segment Executor",
|
|
|
+ module_key="segment_executor",
|
|
|
+ summary="根据 SegmentPackage 制作并封印 SegmentDelivery",
|
|
|
+ branch_key=package.segment_id,
|
|
|
+) as ctx:
|
|
|
+ ...
|
|
|
+```
|
|
|
+
|
|
|
+支持四种 `kind`:
|
|
|
+
|
|
|
+| 常量 | 值 | 用途 |
|
|
|
+|---|---|---|
|
|
|
+| `observe.KIND_AGENT` | `agent` | 带工具、可能循环的 Agent |
|
|
|
+| `observe.KIND_LLM` | `llm` | 单次模型调用、无工具无循环 |
|
|
|
+| `observe.KIND_CODE` | `code` | 确定性代码阶段 |
|
|
|
+| `observe.KIND_WORKFLOW` | `workflow` | 只负责组织其他模块的工作流 |
|
|
|
+
|
|
|
+模块嵌套就是调用关系。内层模块会自动成为外层模块运行流程中的 call 节点,不需要手工连线。
|
|
|
+
|
|
|
+### 6.5 `ctx.declare()`:声明结构与输入
|
|
|
+
|
|
|
+```python
|
|
|
+user_content = ctx.declare(
|
|
|
+ system_prompt=system_prompt,
|
|
|
+ blocks=[
|
|
|
+ InputBlock(
|
|
|
+ "Segment Package",
|
|
|
+ key="segment_package",
|
|
|
+ value=package.model_dump(mode="json"),
|
|
|
+ optional=False,
|
|
|
+ ),
|
|
|
+ InputBlock(
|
|
|
+ "Verified Dependencies",
|
|
|
+ key="verified_dependencies",
|
|
|
+ value=verified_dependencies,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ tools=resolved_tools,
|
|
|
+ model=model_name,
|
|
|
+ runtime={"model": model_name},
|
|
|
+ source_fn=run_segment_executor,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+`declare()` 负责:
|
|
|
+
|
|
|
+- 声明 system prompt;
|
|
|
+- 声明稳定输入槽;
|
|
|
+- 声明真实工具对象及其源码版本;
|
|
|
+- 声明模型和运行参数;
|
|
|
+- 声明确定性代码实现;
|
|
|
+- 返回按输入槽拼好的 prompt 文本。
|
|
|
+
|
|
|
+如果接入处已经有固定的多模态消息且暂时无法拆槽,可使用:
|
|
|
+
|
|
|
+```python
|
|
|
+InputBlock.from_content(user_content)
|
|
|
+```
|
|
|
+
|
|
|
+这只能作为第一阶段脚手架。正式接入应把输入拆成稳定、具名、逐次不变的语义槽。
|
|
|
+
|
|
|
+### 6.6 `InputBlock`:输入槽
|
|
|
+
|
|
|
+常用字段:
|
|
|
+
|
|
|
+| 字段 | 说明 |
|
|
|
+|---|---|
|
|
|
+| `name` | 页面显示名 |
|
|
|
+| `key` | 稳定键,建议使用英文 snake_case |
|
|
|
+| `text` | 文本值 |
|
|
|
+| `images` | 图片 URL 列表 |
|
|
|
+| `items` | 结构化条目 |
|
|
|
+| `item_type` | 条目类型,供前端选择渲染器 |
|
|
|
+| `optional` | 是否可选 |
|
|
|
+| `value` | 普通值或带血缘的 `OutRef` |
|
|
|
+| `origin` | 显式来源引用 |
|
|
|
+| `source` | 人类可读的来源说明 |
|
|
|
+
|
|
|
+输入槽属于模块结构,不能因为某一轮没有值就删除。空值时保留同一个槽,避免同一模块每次运行都生成
|
|
|
+不同结构版本。
|
|
|
+
|
|
|
+### 6.7 `ctx.set_output()`:模块产物
|
|
|
+
|
|
|
+```python
|
|
|
+ctx.set_output(
|
|
|
+ delivery.model_dump(mode="json"),
|
|
|
+ ok=True,
|
|
|
+ images=produced_image_urls,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+规则:
|
|
|
+
|
|
|
+- `data` 只放客观业务产物;
|
|
|
+- token、耗时和步骤数由 SDK 自动采集,不应重复写入;
|
|
|
+- `ok=True` 表示模块本身成功完成;
|
|
|
+- `ok=False` 表示模块执行失败;
|
|
|
+- 不传 `ok` 表示未知,不等于失败;
|
|
|
+- Validator 成功产出 `FAIL` 报告时,Validator 模块本身仍可为 `ok=True`;
|
|
|
+- 只有真正产出图片的模块才传 `images`;
|
|
|
+- 评估模块不能把被评图片声明为自己的产图。
|
|
|
+
|
|
|
+### 6.8 手工补录
|
|
|
+
|
|
|
+未走 LangChain 或需要记录确定性过程时,可使用:
|
|
|
+
|
|
|
+```python
|
|
|
+ctx.record_llm(...)
|
|
|
+ctx.record_tool(...)
|
|
|
+ctx.record_note(...)
|
|
|
+ctx.record_messages(...)
|
|
|
+ctx.record_stage(...)
|
|
|
+```
|
|
|
+
|
|
|
+对应能力:
|
|
|
+
|
|
|
+| 接口 | 用途 |
|
|
|
+|---|---|
|
|
|
+| `record_llm` | 手工记录一次模型调用、reasoning、tool calls 和 token |
|
|
|
+| `record_tool` | 记录不经模型触发的工具调用 |
|
|
|
+| `record_note` | 记录过程说明 |
|
|
|
+| `record_messages` | 保存一次模型调用的消息原件 |
|
|
|
+| `record_stage` | 把确定性代码工序记录成子调用 |
|
|
|
+
|
|
|
+确定性步骤优先使用 `record_stage(fn=真实函数)`,让源码进入模块定义和版本指纹,不要用散文描述代替
|
|
|
+真实规则。
|
|
|
+
|
|
|
+### 6.9 输出血缘
|
|
|
+
|
|
|
+```python
|
|
|
+planner_output = planner_ctx.out()
|
|
|
+
|
|
|
+InputBlock(
|
|
|
+ "Production Plan",
|
|
|
+ key="production_plan",
|
|
|
+ value=planner_output,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+`ctx.out()` 返回带来源引用的 `OutRef`。下游在构造 `InputBlock` 时通过 `value=` 接收,
|
|
|
+观测台即可绘制跨模块血缘。
|
|
|
+
|
|
|
+注意:
|
|
|
+
|
|
|
+- 必须在构造 `InputBlock` 时传 `value=`;
|
|
|
+- `.value` 用于取得裸值;
|
|
|
+- `.field("path")` 用于引用输出中的特定字段。
|
|
|
+
|
|
|
+### 6.10 LangGraph 结构
|
|
|
+
|
|
|
+当前 Production 0.7 的唯一正式控制流位于:
|
|
|
+
|
|
|
+```text
|
|
|
+production_build_agents/production/graph.py
|
|
|
+```
|
|
|
+
|
|
|
+应使用 SDK 的 LangGraph 集成读取真实拓扑:
|
|
|
+
|
|
|
+```python
|
|
|
+from obagent_sdk.integrations.langgraph import graph_spec
|
|
|
+
|
|
|
+graph = create_production_graph(...)
|
|
|
+
|
|
|
+with observe.module(
|
|
|
+ "production_graph",
|
|
|
+ kind=observe.KIND_WORKFLOW,
|
|
|
+ title="Production 0.7",
|
|
|
+ module_key="production_graph",
|
|
|
+ spec=graph_spec(graph),
|
|
|
+) as ctx:
|
|
|
+ result = graph.invoke(...)
|
|
|
+ ctx.set_output(result, ok=...)
|
|
|
+```
|
|
|
+
|
|
|
+`graph_spec(graph)` 会从编译后的图中提取节点、条件边、分支和回边。不要手工复制第二份 Graph
|
|
|
+拓扑,否则业务图改变后可视化会漂移。
|
|
|
+
|
|
|
+LangGraph 节点会被 SDK 自动采集为模块。不要再给每个 Graph 节点机械地包一层
|
|
|
+`observe.module()`;只在节点内部存在独立业务 Agent、模型语义或确定性子阶段时增加申报。
|
|
|
+
|
|
|
+### 6.11 并发
|
|
|
+
|
|
|
+SDK 使用上下文维护父子模块关系。普通线程池不会自动继承上下文。
|
|
|
+
|
|
|
+项目当前在 `production_build_agents/tools/discovery.py` 使用 `ThreadPoolExecutor`。正式接入时
|
|
|
+必须检查该并发是否发生在活跃观测上下文中。如果需要保留父模块,应使用:
|
|
|
+
|
|
|
+```python
|
|
|
+observe.spawn(executor, fn, *args, **kwargs)
|
|
|
+```
|
|
|
+
|
|
|
+或:
|
|
|
+
|
|
|
+```python
|
|
|
+observe.run_parallel(functions, max_workers=8)
|
|
|
+```
|
|
|
+
|
|
|
+一份定义并发执行多个候选时可以使用 `ctx.map(...)`,并为每一路提供稳定的 `branch_key`。
|
|
|
+
|
|
|
+### 6.12 视图契约
|
|
|
+
|
|
|
+SDK 支持 `ViewSpec`、`ViewField` 和 `ViewItems`,用于明确结构化输出如何展示:
|
|
|
+
|
|
|
+- `ViewField(..., as_="text")`
|
|
|
+- `ViewField(..., as_="md")`
|
|
|
+- `ViewField(..., as_="code")`
|
|
|
+- `ViewField(..., as_="json")`
|
|
|
+- `ViewItems(...)`
|
|
|
+
|
|
|
+第一阶段不应为了美化页面提前设计大量 View。先确保真实模块、输入、过程和输出正确,再为
|
|
|
+ProductionPlan、SegmentDelivery、ValidationReport、Artifact 等稳定合同增加专用 View。
|
|
|
+
|
|
|
+## 7. 当前项目的接入架构
|
|
|
+
|
|
|
+### 7.1 总体调用关系
|
|
|
+
|
|
|
+```mermaid
|
|
|
+flowchart TD
|
|
|
+ CLI["run_production.py<br/>加载 .env 与 CLI 参数"]
|
|
|
+ OBS["production_build_agents/observability.py<br/>配置、脱敏、Run 参数"]
|
|
|
+ RUN["observe.run<br/>一次 Production 请求"]
|
|
|
+ GRAPH["production_graph<br/>KIND_WORKFLOW + graph_spec"]
|
|
|
+ PLAN["Production Planner<br/>INITIAL / ADAPT / REPLAN"]
|
|
|
+ SEGEXEC["Segment Executor<br/>工具循环与媒体制作"]
|
|
|
+ SEGVAL["Segment Validator<br/>证据收集与语义验收"]
|
|
|
+ PROGRESS["Progress Review<br/>CONTINUE / ADAPT / REPLAN"]
|
|
|
+ ASSEMBLY["Production Assembly"]
|
|
|
+ READY["Readiness Check"]
|
|
|
+ PRODVAL["Production Validator"]
|
|
|
+ FINAL["Finalize"]
|
|
|
+ STORE["正式 Run 文件、Checkpoint、Journal、Artifact"]
|
|
|
+ REMOTE["obagent 观测台"]
|
|
|
+
|
|
|
+ CLI --> OBS
|
|
|
+ OBS --> RUN
|
|
|
+ RUN --> GRAPH
|
|
|
+ GRAPH --> PLAN
|
|
|
+ GRAPH --> SEGEXEC
|
|
|
+ GRAPH --> SEGVAL
|
|
|
+ GRAPH --> PROGRESS
|
|
|
+ GRAPH --> ASSEMBLY
|
|
|
+ GRAPH --> READY
|
|
|
+ GRAPH --> PRODVAL
|
|
|
+ GRAPH --> FINAL
|
|
|
+ PLAN --> STORE
|
|
|
+ SEGEXEC --> STORE
|
|
|
+ SEGVAL --> STORE
|
|
|
+ ASSEMBLY --> STORE
|
|
|
+ PRODVAL --> STORE
|
|
|
+ FINAL --> STORE
|
|
|
+ RUN -. "旁路遥测" .-> REMOTE
|
|
|
+ STORE -. "只读回放" .-> CLI
|
|
|
+```
|
|
|
+
|
|
|
+### 7.2 顶层 Run 边界
|
|
|
+
|
|
|
+推荐在 `production_build_agents/production/runtime.py` 的 `run_production_graph()` 内部、
|
|
|
+完成恢复状态读取之后创建观测 Run,而不是只在 CLI `main()` 外围包装。
|
|
|
+
|
|
|
+原因:
|
|
|
+
|
|
|
+- `run_production_graph()` 同时服务 CLI、测试和程序调用;
|
|
|
+- 它掌握 fresh、resume、terminal no-op 的真实状态;
|
|
|
+- 它知道 `graph.invoke()` 是否实际发生;
|
|
|
+- 它可以准确设置 `execution_mode`;
|
|
|
+- 不会把读取到终态 Checkpoint 误画成重新执行了 Production Graph。
|
|
|
+
|
|
|
+建议的 execution mode:
|
|
|
+
|
|
|
+| 值 | 含义 |
|
|
|
+|---|---|
|
|
|
+| `fresh` | 没有既有 Checkpoint,从初始状态执行 |
|
|
|
+| `resume` | 从非终态 Checkpoint 恢复并继续执行 |
|
|
|
+| `completed_noop` | 已完成,只读验证后返回,没有再次执行 Graph |
|
|
|
+| `failed_noop` | 已进入正式失败终态,只读验证后返回 |
|
|
|
+
|
|
|
+completed no-op 可以有一条“本次调用”的 Run 记录,但必须:
|
|
|
+
|
|
|
+- `meta.execution_mode="completed_noop"`;
|
|
|
+- 不创建假的 Planner、Executor、Validator 实例;
|
|
|
+- 不创建新的 Segment 轮次;
|
|
|
+- 输出指向既有正式状态;
|
|
|
+- 明确 `graph_invoked=false`;
|
|
|
+- 不把只读重验描述为重新生产。
|
|
|
+
|
|
|
+### 7.3 建议的模块清单
|
|
|
+
|
|
|
+| 稳定 `module_key` | 标题 | `kind` | 真实边界 |
|
|
|
+|---|---|---|---|
|
|
|
+| `production_graph` | Production 0.7 | `workflow` | 编译后的唯一 LangGraph |
|
|
|
+| `production_planner` | Production Planner | `agent` | INITIAL、ADAPT、REPLAN 共用正式 Planner |
|
|
|
+| `segment_executor` | Segment Executor | `agent` | 每个真实 Segment 的工具循环和 Delivery 生成 |
|
|
|
+| `segment_validator_evidence` | Segment Validator Evidence | `code` | 只读证据收集和预校验 |
|
|
|
+| `segment_validator` | Segment Validator | `llm` | 独立语义判断 |
|
|
|
+| `production_progress_review` | Production Progress Review | `llm` 或 `agent` | 正式进度决策 |
|
|
|
+| `production_assembly` | Production Assembly | `agent` 或 `code` | 依据实际工具调用形态确定 |
|
|
|
+| `production_readiness` | Production Readiness | `code` | 确定性媒体就绪检查 |
|
|
|
+| `production_validator` | Production Validator | `agent` | 终片证据与语义验收 |
|
|
|
+| `production_finalize` | Production Finalize | `code` | 正式终态封印 |
|
|
|
+
|
|
|
+`module_key` 不包含 Segment ID。每个 Segment 的区分通过 `branch_key=segment_id`、输入槽和输出
|
|
|
+合同完成。这样同一模块才能跨 Run、跨 Segment 聚合比较。
|
|
|
+
|
|
|
+### 7.4 Segment 轮次
|
|
|
+
|
|
|
+当前 Graph 的 Segment 主循环大致为:
|
|
|
+
|
|
|
+```text
|
|
|
+prepare_next_segment
|
|
|
+ → execute_segment
|
|
|
+ → validate_segment
|
|
|
+ → review_production_progress
|
|
|
+ → prepare_next_segment / adapt_production / replan / assemble
|
|
|
+```
|
|
|
+
|
|
|
+第一阶段建议先不设置 `round_anchor`,跑一个最小真实 Run,确认 SDK 自动生成的模块局部名和父容器。
|
|
|
+确认后再考虑:
|
|
|
+
|
|
|
+```python
|
|
|
+round_anchor={
|
|
|
+ "in": "production_graph",
|
|
|
+ "on": ["prepare_next_segment"],
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+该配置只是候选值,必须以真实页面中的调用层级为准。轮语义会随 Run 持久化,不能靠事后修改修复
|
|
|
+历史 Run,所以不能未经验证直接固化。
|
|
|
+
|
|
|
+Segment ID、Plan Version、Attempt 和 ordinal 应作为结构化输入或 branch key 上报,不能靠解析标题。
|
|
|
+
|
|
|
+## 8. 各业务模块的输入输出方案
|
|
|
+
|
|
|
+### 8.1 Production Planner
|
|
|
+
|
|
|
+建议输入槽:
|
|
|
+
|
|
|
+- `planning_package`
|
|
|
+- `planning_package_ref`
|
|
|
+- `production_brief`
|
|
|
+- `global_data_delivery`
|
|
|
+- `production_input_catalog`
|
|
|
+- `previous_plan`
|
|
|
+- `failure_report`
|
|
|
+- `progress_decision`
|
|
|
+- `mode`
|
|
|
+
|
|
|
+INITIAL、ADAPT、REPLAN 使用同一个 `module_key="production_planner"`,输入槽取三种入口的并集。
|
|
|
+当前模式没有值的槽保留为空,不能拆成三个互不相干的模块。
|
|
|
+
|
|
|
+输出:
|
|
|
+
|
|
|
+```text
|
|
|
+ProductionPlan
|
|
|
+```
|
|
|
+
|
|
|
+`_record_observability()` 当前记录的是本项目自己的落盘 Agent Audit,不是 obagent SDK。正式接入时
|
|
|
+应保留这套审计,不要覆盖、删除或用远端观测替代。
|
|
|
+
|
|
|
+### 8.2 Segment Executor
|
|
|
+
|
|
|
+建议输入槽:
|
|
|
+
|
|
|
+- `segment_package`
|
|
|
+- `segment_id`
|
|
|
+- `plan_version`
|
|
|
+- `package_record_path`
|
|
|
+- `verified_dependencies`
|
|
|
+- `shared_visual_anchor`
|
|
|
+- `allowed_tools`
|
|
|
+- `resume_count`
|
|
|
+- `recovered_tool_progress`
|
|
|
+
|
|
|
+工具必须把实际 Tool 对象传给 `declare(tools=...)`,不能只传工具名字。
|
|
|
+
|
|
|
+输出建议保持正式合同结构:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "candidate": {},
|
|
|
+ "delivery": {},
|
|
|
+ "attempt": {},
|
|
|
+ "outcome": "..."
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+只有真实产出的图片或可远端访问的媒体 URL 才通过 `images=` 声明。远端观测台无法直接访问开发机的
|
|
|
+本地绝对路径;本地 Artifact 路径应作为结构化数据保存,由仓库内 `visualization/` 提供媒体路由。
|
|
|
+
|
|
|
+### 8.3 Segment Validator
|
|
|
+
|
|
|
+建议拆成两个真实阶段:
|
|
|
+
|
|
|
+1. `segment_validator_evidence`:预校验、媒体检查、证据收集,`kind=code`;
|
|
|
+2. `segment_validator`:无工具的语义判断,`kind=llm`。
|
|
|
+
|
|
|
+输出应包含:
|
|
|
+
|
|
|
+- `SegmentValidatorCandidate`
|
|
|
+- `SegmentValidationReport`
|
|
|
+- 六项 Criterion;
|
|
|
+- Evidence;
|
|
|
+- 代码重算后的正式 verdict。
|
|
|
+
|
|
|
+Validator 成功地判定业务失败时:
|
|
|
+
|
|
|
+```text
|
|
|
+模块执行 ok = true
|
|
|
+业务 verdict = FAIL
|
|
|
+```
|
|
|
+
|
|
|
+只有 Validator 自身异常、合同不合法或未能形成正式报告时,模块执行才是 `ok=false`。
|
|
|
+
|
|
|
+### 8.4 Production Assembly 与 Final Validation
|
|
|
+
|
|
|
+阶段 13、14 的业务代码已经在 Production 0.7 Graph 中出现,但其可视化申报仍必须以真实实现为准:
|
|
|
+
|
|
|
+- 有模型和工具循环时使用 `agent`;
|
|
|
+- 纯工具/确定性编排使用 `code` 或 `workflow`;
|
|
|
+- 不预先伪造未来不存在的字段;
|
|
|
+- 只有正式 Assembly Delivery、Readiness Report、Production Validation Report 出现后才声明产物;
|
|
|
+- Finalize 只投影真实终态,不自行推断完成。
|
|
|
+
|
|
|
+## 9. 状态、异常和恢复语义
|
|
|
+
|
|
|
+### 9.1 状态映射
|
|
|
+
|
|
|
+建议同时上报两个维度:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "execution_ok": true,
|
|
|
+ "business_status": "COMPLETED",
|
|
|
+ "verdict": "PASS",
|
|
|
+ "outcome": "KNOWN"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+不能只用一个布尔值承载所有语义。
|
|
|
+
|
|
|
+### 9.2 `OUTCOME_UNKNOWN`
|
|
|
+
|
|
|
+当远端工具可能已经产生副作用但本地没有确定结果时:
|
|
|
+
|
|
|
+- 模块 `ok` 不应写成 `True`;
|
|
|
+- 输出明确记录 `outcome="OUTCOME_UNKNOWN"`;
|
|
|
+- 保留 operation scope、tool call ID、Attempt、ordinal 和已知证据;
|
|
|
+- 不重发已经可能成功的付费生成请求;
|
|
|
+- 观测台只展示事实,不替业务层决定恢复策略。
|
|
|
+
|
|
|
+### 9.3 异常
|
|
|
+
|
|
|
+`observe.run()` 和 `observe.module()` 不应吞业务异常。正确模式:
|
|
|
+
|
|
|
+```python
|
|
|
+with observe.module(...) as ctx:
|
|
|
+ result = business_call()
|
|
|
+ ctx.set_output(result, ok=True)
|
|
|
+```
|
|
|
+
|
|
|
+如果 `business_call()` 抛异常:
|
|
|
+
|
|
|
+- SDK 自动把模块标为失败并记录错误;
|
|
|
+- 异常继续向外抛;
|
|
|
+- 原有 Production 恢复、重试、Checkpoint 和退出码逻辑继续生效。
|
|
|
+
|
|
|
+不要为了上报而新增捕获后返回成功的代码。
|
|
|
+
|
|
|
+## 10. 隐私、安全与数据量
|
|
|
+
|
|
|
+### 10.1 自动采集范围
|
|
|
+
|
|
|
+`auto_collect=True` 会自动采集当前上下文中的 LangChain/LangGraph:
|
|
|
+
|
|
|
+- 模型输入消息;
|
|
|
+- system prompt;
|
|
|
+- 模型输出和 reasoning;
|
|
|
+- tool calls;
|
|
|
+- 工具入参和结果;
|
|
|
+- token、耗时、模型信息;
|
|
|
+- 调用时序。
|
|
|
+
|
|
|
+这意味着接入前必须确认 Production 数据允许发送到该观测台。
|
|
|
+
|
|
|
+### 10.2 当前地址是 HTTP
|
|
|
+
|
|
|
+当前观测台地址为:
|
|
|
+
|
|
|
+```text
|
|
|
+http://8.147.104.190:8931
|
|
|
+```
|
|
|
+
|
|
|
+它不是 HTTPS。不要在未经授权的情况下上报:
|
|
|
+
|
|
|
+- API Key、Cookie、Token、密码;
|
|
|
+- 用户个人信息;
|
|
|
+- 未脱敏的内部 URL 查询参数;
|
|
|
+- Base64 媒体正文;
|
|
|
+- 本地 `.env` 内容;
|
|
|
+- 不必要的完整文件内容;
|
|
|
+- 第三方受限素材。
|
|
|
+
|
|
|
+生产环境正式启用前,应确认网络边界、访问控制、保留周期和鉴权配置。
|
|
|
+
|
|
|
+### 10.3 脱敏和裁剪
|
|
|
+
|
|
|
+建议适配层统一提供:
|
|
|
+
|
|
|
+```python
|
|
|
+jsonable_for_observation(value)
|
|
|
+redact_observation_value(value)
|
|
|
+compact_observation_value(value, max_chars=...)
|
|
|
+```
|
|
|
+
|
|
|
+原则:
|
|
|
+
|
|
|
+- 正式合同保留关键 ID、状态、hash、版本和引用;
|
|
|
+- 超长正文给摘要和正式 Artifact/Record 引用;
|
|
|
+- 不重复上传媒体二进制;
|
|
|
+- 不修改业务对象本身;
|
|
|
+- 脱敏逻辑只作用于观测副本。
|
|
|
+
|
|
|
+## 11. 健康检查、查询和排障
|
|
|
+
|
|
|
+### 11.1 SDK 体检
|
|
|
+
|
|
|
+```bash
|
|
|
+.venv/bin/python -m obagent_sdk doctor \
|
|
|
+ --endpoint http://8.147.104.190:8931
|
|
|
+```
|
|
|
+
|
|
|
+该命令只验证:
|
|
|
+
|
|
|
+- 当前机器到观测台是否可达;
|
|
|
+- 服务端版本是否能读取;
|
|
|
+- 本地 WAL 是否有积压。
|
|
|
+
|
|
|
+它是独立进程,看不到应用代码中 `configure()` 的实际配置。
|
|
|
+
|
|
|
+### 11.2 HTTP 健康检查
|
|
|
+
|
|
|
+```bash
|
|
|
+curl -fsS http://8.147.104.190:8931/api/health
|
|
|
+```
|
|
|
+
|
|
|
+已验证返回:
|
|
|
+
|
|
|
+```json
|
|
|
+{"ok": true, "version": "0.1.0"}
|
|
|
+```
|
|
|
+
|
|
|
+### 11.3 查询 Run
|
|
|
+
|
|
|
+以下是当前服务端已验证的只读接口:
|
|
|
+
|
|
|
+```bash
|
|
|
+curl -fsS \
|
|
|
+ 'http://8.147.104.190:8931/api/runs?project=video_image_production_build&page=1&page_size=30'
|
|
|
+
|
|
|
+curl -fsS \
|
|
|
+ 'http://8.147.104.190:8931/api/runs/<server_run_id>'
|
|
|
+```
|
|
|
+
|
|
|
+这些接口适合诊断和把 SDK 客户端 UID 映射到服务端数字 ID。业务正确性不能依赖观测台查询成功。
|
|
|
+
|
|
|
+### 11.4 WAL
|
|
|
+
|
|
|
+默认 WAL 目录:
|
|
|
+
|
|
|
+```text
|
|
|
+~/.obagent/wal
|
|
|
+```
|
|
|
+
|
|
|
+上报失败时可检查并重放:
|
|
|
+
|
|
|
+```bash
|
|
|
+.venv/bin/python -m obagent_sdk replay \
|
|
|
+ --endpoint http://8.147.104.190:8931
|
|
|
+```
|
|
|
+
|
|
|
+重放只处理遥测,不得重新执行 Production 业务步骤。
|
|
|
+
|
|
|
+### 11.5 离线 SDK 文档
|
|
|
+
|
|
|
+```bash
|
|
|
+.venv/bin/python -m obagent_sdk docs
|
|
|
+.venv/bin/python -m obagent_sdk docs quickstart
|
|
|
+.venv/bin/python -m obagent_sdk docs integrating
|
|
|
+.venv/bin/python -m obagent_sdk docs api
|
|
|
+.venv/bin/python -m obagent_sdk docs troubleshooting
|
|
|
+.venv/bin/python -m obagent_sdk docs changelog
|
|
|
+```
|
|
|
+
|
|
|
+## 12. 最小连通性测试
|
|
|
+
|
|
|
+以下测试只验证 SDK 到观测台的写入和展示,不调用模型或媒体生成服务:
|
|
|
+
|
|
|
+```python
|
|
|
+from obagent_sdk import configure, observe
|
|
|
+
|
|
|
+
|
|
|
+configure(
|
|
|
+ endpoint="http://8.147.104.190:8931",
|
|
|
+ project="video_image_production_build",
|
|
|
+)
|
|
|
+
|
|
|
+with observe.run(
|
|
|
+ agent="sdk_connectivity_test",
|
|
|
+ objective="obagent-sdk 接入连通性测试",
|
|
|
+ project_name="VideoImageProductionBuild",
|
|
|
+ payload={"test": True},
|
|
|
+ meta={
|
|
|
+ "run_name": "SDK 连通性测试 · VideoImageProductionBuild",
|
|
|
+ "temporary": True,
|
|
|
+ },
|
|
|
+) as rh:
|
|
|
+ with observe.module(
|
|
|
+ "connectivity_probe",
|
|
|
+ kind=observe.KIND_CODE,
|
|
|
+ title="SDK 上报链路探针",
|
|
|
+ module_key="connectivity_probe",
|
|
|
+ ) as ctx:
|
|
|
+ ctx.declare(
|
|
|
+ blocks=[
|
|
|
+ observe.InputBlock(
|
|
|
+ "检测目标",
|
|
|
+ "http://8.147.104.190:8931",
|
|
|
+ key="endpoint",
|
|
|
+ optional=False,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ ctx.record_note("SDK 写入链路已执行", ok=True)
|
|
|
+ ctx.set_output(
|
|
|
+ {"endpoint_reachable": True},
|
|
|
+ ok=True,
|
|
|
+ )
|
|
|
+ rh.finish(
|
|
|
+ final_output={"status": "passed"},
|
|
|
+ ok=True,
|
|
|
+ )
|
|
|
+```
|
|
|
+
|
|
|
+## 13. 分阶段实施方案
|
|
|
+
|
|
|
+### 阶段 A:依赖与集中配置
|
|
|
+
|
|
|
+改动范围:
|
|
|
+
|
|
|
+- 将 `obagent-sdk` 加入项目依赖和锁文件;
|
|
|
+- 新增集中观测适配器;
|
|
|
+- 在 `.env.example` 或配置文档中声明 `OBAGENT_*`;
|
|
|
+- 添加配置、禁用和降级测试。
|
|
|
+
|
|
|
+验收:
|
|
|
+
|
|
|
+- `doctor` 全绿;
|
|
|
+- 禁用时无远端写入;
|
|
|
+- endpoint 不可达时业务仍按原逻辑完成或失败;
|
|
|
+- WAL 行为符合预期。
|
|
|
+
|
|
|
+### 阶段 B:零申报 Run
|
|
|
+
|
|
|
+只增加顶层 `observe.run()`,暂不增加大量业务模块申报。
|
|
|
+
|
|
|
+验收:
|
|
|
+
|
|
|
+- fresh、resume、completed no-op 可以区分;
|
|
|
+- Run 的 objective、thread ID、协议版本、耗时和最终状态正确;
|
|
|
+- LangChain/LangGraph 自动采集存在;
|
|
|
+- 不改变正式 Run 目录和文件 hash。
|
|
|
+
|
|
|
+### 阶段 C:Production Graph
|
|
|
+
|
|
|
+增加:
|
|
|
+
|
|
|
+- `production_graph` workflow;
|
|
|
+- `graph_spec(compiled_graph)`;
|
|
|
+- 条件边和回边的页面验证;
|
|
|
+- 候选 `round_anchor` 的真实 Run 验证。
|
|
|
+
|
|
|
+验收:
|
|
|
+
|
|
|
+- 页面拓扑与 `graph.py` 一致;
|
|
|
+- 未走分支仍显示为定义,但不伪造运行实例;
|
|
|
+- Loop 次数与真实 Segment 推进一致;
|
|
|
+- Graph 节点没有被重复包装成两套模块。
|
|
|
+
|
|
|
+### 阶段 D:阶段 12 业务模块
|
|
|
+
|
|
|
+优先接入:
|
|
|
+
|
|
|
+- Production Planner;
|
|
|
+- Segment Executor;
|
|
|
+- Segment Validator Evidence;
|
|
|
+- Segment Validator;
|
|
|
+- Progress Review。
|
|
|
+
|
|
|
+验收:
|
|
|
+
|
|
|
+- 每个真实 Segment 有独立 branch/实例;
|
|
|
+- 多 Segment 工具调用不会串线;
|
|
|
+- Package、Candidate、Delivery、Report 和 Evidence 是结构化 JSON;
|
|
|
+- 工具对象可以查看真实定义;
|
|
|
+- PASS、FAIL、CONTRACT_INVALID、OUTCOME_UNKNOWN 和恢复 Attempt 都保持原语义。
|
|
|
+
|
|
|
+### 阶段 E:阶段 13、14
|
|
|
+
|
|
|
+在真实实现稳定后接入:
|
|
|
+
|
|
|
+- Assembly;
|
|
|
+- Readiness;
|
|
|
+- Production Validator;
|
|
|
+- Finalize;
|
|
|
+- 最终媒体和 Artifact View。
|
|
|
+
|
|
|
+不为未来阶段预造虚假模块或合同字段。
|
|
|
+
|
|
|
+### 阶段 F:视图优化
|
|
|
+
|
|
|
+数据正确后再增加:
|
|
|
+
|
|
|
+- ProductionPlan View;
|
|
|
+- Segment Timeline View;
|
|
|
+- Criterion/Evidence View;
|
|
|
+- Artifact View;
|
|
|
+- 图片、视频、音频、字幕和 JSON 的专用展示。
|
|
|
+
|
|
|
+视图优化不能改变上报事实和业务状态。
|
|
|
+
|
|
|
+## 14. 测试矩阵
|
|
|
+
|
|
|
+| 场景 | 预期 |
|
|
|
+|---|---|
|
|
|
+| SDK 禁用 | 无远端数据,业务行为不变 |
|
|
|
+| endpoint 不可达 | 业务继续,遥测进 WAL 或降级 |
|
|
|
+| Plan-only | 只有真实 Planner/Plan 实例 |
|
|
|
+| Segment Package-only | 不伪造 Executor 已运行 |
|
|
|
+| Executor 运行中 | 展示真实工具过程,不提前出现 Delivery |
|
|
|
+| Delivery 待验收 | Executor 成功,Validator 尚无终态 |
|
|
|
+| Segment PASS | Report 与 Summary 为正式 PASS |
|
|
|
+| Segment FAIL | Validator 执行成功,业务 verdict 为 FAIL |
|
|
|
+| CONTRACT_INVALID | 显示合同错误,不改写为普通模型失败 |
|
|
|
+| OUTCOME_UNKNOWN | 显示未知副作用,不自动重试付费工具 |
|
|
|
+| resume | 使用同一业务 thread 身份,显示恢复信息 |
|
|
|
+| completed no-op | 不出现新业务模块实例和新 Segment 轮次 |
|
|
|
+| 多 Segment | branch、tool call、Artifact 和 ordinal 隔离 |
|
|
|
+| Assembly/Final Validation | 只显示真实执行过的阶段 |
|
|
|
+
|
|
|
+## 15. 最终验收清单
|
|
|
+
|
|
|
+- [ ] SDK 版本与项目依赖、锁文件一致。
|
|
|
+- [ ] `configure()` 在 `.env` 加载后、第一次 Run 前执行。
|
|
|
+- [ ] endpoint、project、enabled 和 api_key 均由本项目配置体系显式传入。
|
|
|
+- [ ] 顶层 Run 能区分 fresh、resume 和 terminal no-op。
|
|
|
+- [ ] `graph_spec()` 来自真实编译 Graph,没有第二份手写拓扑。
|
|
|
+- [ ] 模块边界是业务边界,没有机械重复包装 LangGraph 节点。
|
|
|
+- [ ] 同一业务模块跨 Run 使用稳定 `module_key`。
|
|
|
+- [ ] Segment ID 使用 `branch_key` 或结构化字段,不写进 `module_key`。
|
|
|
+- [ ] 输入是稳定具名槽,空槽不会被删除。
|
|
|
+- [ ] 工具传真实对象,不传名字字符串。
|
|
|
+- [ ] 输出为真实 JSON Contract,不塞重复 token/耗时。
|
|
|
+- [ ] Validator 的执行成功与业务 verdict 分开表达。
|
|
|
+- [ ] 图片只挂在真实产图模块。
|
|
|
+- [ ] completed no-op 不伪造重新执行。
|
|
|
+- [ ] OUTCOME_UNKNOWN 保留未知副作用语义。
|
|
|
+- [ ] 现有 Agent Audit、Checkpoint、Journal 和 Artifact 不受影响。
|
|
|
+- [ ] 上报失败不改变业务返回值、异常、退出码或落盘文件。
|
|
|
+- [ ] 并发任务保持正确父子上下文。
|
|
|
+- [ ] 敏感数据、密钥和媒体正文没有被上报。
|
|
|
+- [ ] 页面模块、输入、过程、输出、分支和 Loop 与真实 Run 一致。
|
|
|
+- [ ] 浏览器控制台无 obagent 相关错误。
|
|
|
+- [ ] 本地 WAL 无非预期积压。
|
|
|
+
|
|
|
+## 16. 参考实现
|
|
|
+
|
|
|
+已参考同仓库族中的成熟接入:
|
|
|
+
|
|
|
+```text
|
|
|
+/Users/samlee/Documents/works/image_article_comprehension/aiddit/production_destruction_agent/framework/observability.py
|
|
|
+```
|
|
|
+
|
|
|
+该项目的关键做法:
|
|
|
+
|
|
|
+- 由宿主读取 `OBAGENT_ENDPOINT`,再显式调用 `configure()`;
|
|
|
+- 用 `observe.run()` 包裹完整业务 Run;
|
|
|
+- 在公共 Agent 基类中统一接入 `observe.module()`;
|
|
|
+- 子类只覆盖标题、输入槽、dispatch node 和输出媒体;
|
|
|
+- LangChain 模型与工具过程交给 SDK 自动采集;
|
|
|
+- `set_output()` 和 `finish()` 只声明作者知道而 SDK 无法推断的业务事实;
|
|
|
+- 上报和服务端 ID 查询均采用旁路容错,不影响主业务。
|
|
|
+
|
|
|
+VideoImageProductionBuild 应复用上述原则,但模块划分必须以自身 Production 0.7 Graph、正式
|
|
|
+Contract、恢复语义和 Segment 工具边界为准,不能直接照搬对方的模块名称或输入结构。
|