跳到正文

30-搭建过程与问题解决台账(M1–M4) ​

一句话:工程实录把每一次“跑通没跑通”沉淀为现象、根因、证据三件套:源码锚点区分环境问题与官方缺陷,复跑命令证明结论尚未过期,关键 ID 与证据文件留档供交叉核对;一旦记录退化成过程叙事,重建环境时就答不出“这个坑还在不在”,旧结论也无从支撑新决策。

定位:开源生态企业智能体平台(agentscope-service)从环境基线到端到端链路走通的工程实录。 口径:本平台 = 基于开源组件(agentscope-java 官方主线)构建的企业级智能体平台,能力口径按《01-落地方法论与总体架构》《24-白皮书对标与落地推演》。 本台账记录每一步做了什么、遇到什么问题、根因是什么、怎么解决、以什么证据确认。结论可复核,命令可复跑。


0. 里程碑总览 ​

里程碑内容状态关键产物
M1环境基线:构建/部署条件盘点✅JDK21+Maven 3.9.9、Docker Desktop、ACR 镜像可用性
M2源码构建(官方 main + openai 扩展)✅service-dataplane-2.1.0-SNAPSHOT.jar(142MB,含 openai 扩展)、as-dataplane:local-openai 镜像
M3全栈 compose 部署✅4 服务(gateway/control/data/scheduler)+ PG17,健康 UP
M4端到端链路走通✅Login→Environment→Agent(managed)→Session→Turn→模型回答 全链路闭环
M5验收矩阵抽测✅ API 侧完成(2026-10-25)幂等✅、SSE✅、工具✅、MCP 运行时✅、审批流运行时✅、多 agent/workspace 能力面✅;遗留:UI Chat(搁置)、skill 运行时接线
M6文档↔运行时对照修正⏳本台账即 M6 的一部分;待补:性能/首 token 延迟分布、SSE 环节数逐跳实测

1. M1 环境基线 ​

项值
JDKD:\Java\jdk-21.0.8(构建要求 21)
MavenD:\Java\apache-maven-3.9.9
Docker DesktopC:\Users\Administrator\AppData\Local\Programs\DockerDesktop\Docker Desktop.exe(不在 Program Files)
compose 工程agentscope-service(deploy 目录)
网关入口http://localhost:18080(= gateway 8080 映射)
数据库PostgreSQL 17(db 容器),库 agentscope,schema:dp(dataplane 29 表)/ rt(runtime 67 表)

已知环境限制(重要,避免重复踩坑) ​

  1. docker.io 直连 443 超时(IPv6 路由问题):所有镜像必须走本机缓存或 ACR(sca-registry.cn-hangzhou.cr.aliyuncs.com/agentscope/*:2.1.0-BETA1);基础镜像拉取也会失败,需用本地已有镜像做 base。
  2. PowerShell 直接 stdout 打印 API 结果会抽风:一律写临时文件再 Read。
  3. 中文路径(02-项目代码)会破坏 protoc 原生编译:mvn 构建必须在纯 ASCII 路径(本次用 D:\build\agentscope-java)。

2. M2 源码构建 ​

2.1 代码基线选择(用户拍板:以官方为主) ​

  • 用户多次纠正调研方法后明确:"落地是 KPI""以官方为主""本地该回退代码回退,用官方的"。
  • 回退动作:
    • 本地 main(1203 commits 领先 + DataPlaneConfig 被 patch 成 provider-neutral)弃用;
    • 备份:分支 backup-pre-official(原 main HEAD)+ stash pre-official-rollback;
    • 切官方 origin/release/2.1.0-BETA1(= ACR 镜像代码)验证后,最终切官方主线 official-main(HEAD=d04529e9 fix(harness): preserve attachments...)。

2.2 为什么必须本地构建(模型对接的选型过程) ​

候选实测结论结论
官方 ACR 镜像(release 2.1.0-BETA1)DataPlaneConfig @ConditionalOnExpression('${builder.dashscope.api-key...}') 固定建 DashScopeChatModel,只走 dashscope 原生协议❌ 接不了兼容网关
官方 release/main 分支代码同官方镜像:dashscope-only 打包(pom 只有 dashscope 扩展)+ 原生协议❌ 需加 openai 扩展
token-plan 网关(sk-sp key)原生 /api/v1/services/aigc/ → 400;compatible-mode /chat/completions → 200(qwen3.8-flash 有回包)只支持 OpenAI 兼容协议
dashscope 官方(sk-ws key)qwen-max/qwen-plus → 200;qwen3.8-flash → 400 url error(官方无此模型名)用户坚持 qwen3.8-flash → 需兼容网关
maas 网关(sk-ws key,https://maas.qianwenaiapi.com/compatible-mode/v1)qwen3.8-flash → 200✅ 可用

最终选型:官方 main 代码本地构建(唯一改动 = service-dataplane pom 加 agentscope-extensions-model-openai 依赖)+ agent 定义 model: openai:qwen3.8-flash + OPENAI_API_KEY/OPENAI_BASE_URL 环境变量指向 token-plan 网关。

2.3 构建问题与解决 ​

问题根因解决
mvn 构建在 agentscope-extensions-controlplane 失败:PROTOC FAILED: ... target\proto: directory does not exist中文路径:protoc 原生 exe 用 ANSI 代码页解析路径,02-项目代码 被读成 02-???????,找不到 proto 文件整树 robocopy 到 ASCII 路径 D:\build\agentscope-java(排除 target/.git/.pylibs),在 D:\build 下构建成功
-Dmaven.javadoc.skip=true 报 Unknown lifecycle phasePowerShell 对带 . 的 -D 参数拆分参数全部加引号:& $mvn "-B" "-ntp" "-pl" "..." ...
镜像构建 FROM eclipse-temurin:21-jre 拉取失败docker.io 直连 443 超时(IPv6)新建 Dockerfile.local-openai:FROM 本地已有的官方 ACR data 镜像 + COPY 新 jar 覆盖 /app.jar

2.4 构建产物验证 ​

  • D:\build\agentscope-java\agentscope-service\service-dataplane\target\service-dataplane-2.1.0-SNAPSHOT.jar(142,638,463 bytes)
  • jar 内确认:BOOT-INF/lib/agentscope-extensions-model-openai-2.1.0-SNAPSHOT.jar ✅(openai 扩展已打入)
  • 镜像:as-dataplane:local-openai(1.01GB)

3. M3 全栈部署 ​

  • compose 四服务:gateway(8080→18080)/control(8081)/data(8082)/scheduler(8083) + postgres:17。
  • 官方 ACR 镜像(control/gateway/scheduler)+ 本地 data 镜像(本次替换)。
  • 健康检查:/actuator/health → UP(data 首次启动约 7 秒)。

配置改动(deploy 目录) ​

  • .env:DASHSCOPE_API_KEY 置空(避免 dashscope 默认 bean 干扰);新增 OPENAI_API_KEY=sk-sp-…(token-plan key)、OPENAI_BASE_URL=https://token-plan.maas.qianwenaiapi.com/compatible-mode/v1。
  • compose.yaml:x-runtime-env 锚点新增 OPENAI_API_KEY/OPENAI_BASE_URL 透传;data 服务 image: as-dataplane:local-openai。

4. M4 端到端链路(全部运行时坐实) ​

4.1 链路顺序与 API ​

步骤请求关键返回
登录POST /api/auth/login(admin / 密码=deploy.env 的 CONTROL_PLANE_BOOTSTRAP_PASSWORD)JWT(7 天)+ userId=user-e1cef194a7ce(roles: user,admin)
命名空间GET /api/v1/me/namespacestenant=default,Personal namespace=personal-2fc9756ccf936edc09a1
环境POST /api/environments {"name":"Quickstart local","type":"local","config":env_d17e35381ab7
AgentPOST /api/v1/agents(官方格式:顶层 binding:{kind:"managed"} + X-AgentScope-Tenant/X-AgentScope-Namespace header;definition 内 defaultEnvironmentId + model:"openai:qwen3.8-flash")agent=86a8ba5b-53e2-41b3-be27-acaf310cf27c(active)、binding=50cabcc6-5fef-5768-94e1-6e4d7af05b83、definition.model 已落库
SessionPOST /api/v1/agent-sessions {"target":{"type":"agent","id":…}}23c43553-16a5-5dfb-8efb-b8a25929f3d3(runtimeKind=managed、挂 env)
TurnPOST .../turns + Idempotency-Key202 queued,返回 eventsUrl/snapshotUrl/statusUrl(原生异步语义)
结果GET .../turns/{id} / GET .../snapshotturn completed,模型回答在 result

注意:此前用旧格式(binding 放 definition 内、无 tenant header)创建 session 报 store: conflict(400)。官方 main 的 agent 创建格式必须照 create-managed-agent.md:binding 在顶层、definition 内用 system/defaultEnvironmentId/model/tools,并带租户 header。

4.2 模型回答证据(snapshot) ​

  • usage.models:model=qwen3.8-flash ×2 次调用,均 completed;耗时 6.59s / 7.52s;含 reasoningTokens(256/160,推理模型特征);总 token 14734。
  • message_id=chatcmpl-…:OpenAI 兼容协议回包 ID(佐证走了 token-plan compatible-mode)。
  • Agent 自主工具调用:memory_search(query "用户 偏好 语言" → 无记忆命中)与 list_files(返回容器根文件清单,含 /app.jar、/data)——记忆检索与 workspace 感知原生可用。
  • 事件序列:input.applied → item.completed(USER) → item.completed(ASSISTANT tool_use) → tool_result ×2 → final_output → run.ended(MODEL_STOP) → turn.completed。
  • session.runtimeStatus=idle(执行完回闲置)。

4.3 中文链路与历史会话 ​

  • 第一轮(PowerShell 默认编码)中文消息变乱码 ??,?????????,模型正确识别为乱码并主动说明——侧面证明模型收到并处理了内容。
  • 第二轮用 UTF-8 字节([System.Text.Encoding]::UTF8.GetBytes)发送"你好,请用一句话介绍你自己。"→ 回答"你好!我是你的编码助手……" ✅ 中文正常 + 同 session 历史连续性坐实。

4.4 M4 端到端链路(mermaid 版) ​


5. 问题解决台账(M1–M4 全量) ​

#问题(现象)根因解决证据
1Turn 报 JdbcStore putIfVersion (insert) failedSQLException 被 JdbcStore 吞包成 IllegalStateException(只留 message);PG 服务端 ERROR: value too long for type character varying(255):runtime 用长路径做 item_key 超 255ALTER TABLE dp.agentscope_store ALTER COLUMN item_key TYPE VARCHAR(2048);PG 容器日志 + JdbcStore.java 源码
2Turn 报 NullPointerException: Model.getModelName() ... model is null官方镜像 DataPlaneConfig dashscope-only,DASHSCOPE_API_KEY 未配置 → 无默认模型 bean配置模型(见 #3)data 日志
3官方镜像接不了 token-plan(401/400)官方镜像只支持 dashscope 原生协议;token-plan 只支持 OpenAI 兼容协议本地构建官方 main + openai 扩展;agent model: openai:qwen3.8-flash;env OPENAI_API_KEY/BASE_URL4 组协议实测(原生 400 / 兼容 200 / 官方 qwen3.8-flash 400 / maas qwen3.8-flash 200)
4mvn 构建 protoc 失败中文路径破坏 protoc 路径解析ASCII 路径 D:\build 构建构建日志 + 成功产物
5PowerShell -Dxxx=yyy 参数解析错pwsh 对带 . 参数拆分引号包裹全部参数构建日志
6docker build 拉 eclipse-temurin 失败docker.io IPv6 直连超时FROM 本地 ACR data 镜像覆盖 jarDockerfile.local-openai
7创建 session 400 store: conflictagent 创建用了旧格式(binding 在 definition 内、无租户 header、无 defaultEnvironmentId)严格按官方 create-managed-agent.md 格式重建HTTP 200 + 完整 agent/binding/definition 响应
8中文消息乱码PowerShell 默认 ANSI 编码发送 bodyUTF-8 字节发送第二轮中文回答正常
9控制台 UI Chat 发消息无回答(新会话)UI chat 会话(sess_9cdaf7901f94)turn 未进入执行管线:rt.execution_attempts 无记录、data 无 PRE_CALL/模型调用;dp.builder_session_event 出现大量 ux_builder_session_event_seq duplicate key WARN(并发写入竞争重试,事件最终完整写入 79 条 seq 1-79,非丢失);control 日志 GET /api/v1/events 持续 403(legacy 通知轮询接口权限拒绝)API 链路不受影响(三个 turn 全部 completed);UI Chat 路径判为官方 main 控制台前后端运行时缺陷,记入 M5/M6 排查(chat_handler 会话体系映射、events 403、turn 分发条件)DB 查询(execution_attempts 空、事件表 79 条)+ control/data 日志
10控制台 UI Chat 读历史会话为空打开 API 创建的成功会话(23c43553,3 轮 completed)显示 Conversation 0;UI chat id(b35336bb 等)与 API session id 是两套体系,UI 侧消息读取未映射到 agent-sessions 数据待 M5/M6 排查 chat 会话数据源映射;API 侧会话消息完整(snapshot/turns 均正常)UI 浏览器观察 + API 查询对比

5.5 M5 验收矩阵抽测(进行中,2026-10-25) ​

方法:复用 M4 成功会话 23c43553,API 侧逐项抽测,证据存 D:\build\_m5_*.txt。API 链路始终作为基准(不受 UI Chat 缺陷影响)。

#验收项方法结果证据
M5-1幂等同键同体同 Idempotency-Key(m5-idem-001)连续两次 POST /turns✅ 两次请求返回同一 turn id(1322bc19),第二次未重复执行;turn completed,result=IDEMPOTENT(模型只回答一次)_m5_idem.txt(两次 HTTP 202 同 id)+ turn 状态查询
M5-2SSE 事件流GET .../events/stream(curl -N)✅ 完整事件链:session.status_running → context_initialized → run.started → input.applied → item.completed(USER) → item.started(model) → item.delta(含 chatcmpl-… message_id)→ …;每个事件带 cursor(base64 inv:{session}:{seq})→ 断点续传机制坐实_m5_sse.txt(30 行首段)
M5-3工具/skill(definition 级)运行时实证(2026-10-25)✅ 工具调用运行时已证(M4:memory_search + list_files 自主调用);skill 用户上传链路全通:PUT /api/agents/{id}/skills/workspace/{name}(markdown+resources)→ 落 agent workspace skills/{name}/SKILL.md(origin=custom)→ PATCH definition.skills=[{type:"workspace",name:"weather-reporter"}] 启用(乐观锁 version)→ data 面 FileSystemSkillRepository 按 front matter 校验加载。关键约束(已踩坑):SKILL.md 必须带 YAML front matter(--- name + description ---),否则 The SKILL.md must have a YAML Front Matter… WARN 且 skill 不注入 prompt。遗留疑点:session workspace 物化的 skills 目录内容存在旧快照(PUT 更新后新 session 仍读到旧内容,疑物化时序/缓存,待 M6 定论);模型对 skill 指令有自主取舍(skill 注入≠强制执行)_skill_put2.txt(235B front matter 落盘)+ _skill_def_patch.txt + _skill_logs3.txt(front matter WARN)+ _skill_file.txt(容器落盘 152B vs 235B 差异)
M5-4MCP 能力确认运行时实证(2026-10-25)✅ 全链路闭环:agent definition mcpServers:[{name:"everything",url:"http://host.docker.internal:3001/mcp"}] PATCH 落库(version=3)→ data 面 McpClientManager: MCP client 'everything' registered successfully + McpServerRegistrar: Registered MCP server 'everything' (transport=http) → 工具全量注册(everything__echo/get-sum…)→ 模型自主调用 everything__echo(`POST_REASONINGtool_call: id=call_bebbd07c… name=everything__echo)→ 工具执行 success 返回 Echo: 你好MCP → tool_result 回填 → 模型终答 → turn completed。证据:_mcp_snapshot.json/_mcp_snap2.json(完整执行链)、_mcp_logs.txt(data 日志)、agent_def_patch2.txt(PATCH 200)。附带踩坑:更新 API 为 PATCH /api/v1/agents/{id}/definition(PUT 404)+ body 需 version(乐观锁,缺则 400);MCP server 探测须带 Accept: application/json, text/event-stream(否则 406);GET /mcp返回 len=0 属正常(streamable-http 只认 POST)。**契约级核对**:mcpServers 声明[{name,url,transport,command}]、transport http/streamable-http/sse/stdio 校验、Name ^[A-Za-z0-9-]{1,64}$禁__、vault→MCP env 注入、mcp_connection_failed_error` 处理——运行时全部吻合
M5-5审批(requireApproval)运行时实证(2026-10-25)✅ 双路径确认:①personal chat 场景(managed session):模型工具调用 → data 面自动挂起 required_action(kind=confirmation,approvalId=b1a7d579,session.runtimeStatus=requires_action,stopReason.tool_confirmation + expiresAt)→ 批准 API POST /api/sessions/{data-session-id}/events body {"events":[{"type":"user.tool_confirmation","payload":{"tool_use_id":…,"allow":true}}]} → HTTP 200 status=approved(source=personal_chat,data 面 HITL)→ 工具继续执行 → turn completed;②AgentTask/协作场景:requestManagedToolApproval(managed_tool_approval.go)落库 rt.approvals(TargetType=execution_attempt,ApproverRef=task.AccountableHumanRef/issue.Creator/ManagedOwnerRef),决策走 control POST /api/v1/approvals/{approvalId}/decide(body: status/expectedVersion>0;approver 外 403;过期/失配 409)。架构结论:personal chat 的 tool confirmation 不落 collaboration 审批表(rt.approvals 空属正常),由 data 面 HITL 直接裁决;审批人=当前会话用户(admin=user-e1cef194a7ce 即 session owner)。UI"允许工具调用"按钮 = 该 events API(体验层复用点)_confirm_allow.txt(200 approved)+ _mcp_snap2.json + managed_tool_approval.go
M5-6多 agent(链路 5)源码✅ definition 原生 multiagent 字段(ManagedDefinitionInput),官方支持主/子 agent 声明managed_definition.go
M5-7workspace(链路 3)运行时✅ agent definition 自动分配 workspacePath=/data/workspaces/user-e1cef194a7ce/86a8ba5b-…(容器侧),隔离目录已就位_agent2.json definition 段

M5 结论(更新):API 侧核心验收项——幂等 ✅ / SSE 事件流+cursor 续传 ✅ / 工具 ✅ / MCP 运行时全链路 ✅ / 审批流运行时(personal chat HITL + AgentTask collaboration 双路径)✅ / skill 用户上传+启用链路 ✅(front matter 约束已踩坑记录) / 多 agent / workspace 能力面确认 ✅。仅剩 UI Chat 缺陷(#9/#10,用户拍板搁置)。M5 API 侧验收完成。

5.5.1 skill 配置模型 / 记忆存储 / 任务分发(2026-10-25 源码+运行时双证) ​

① skill 配置模型(官方三通道,回答"是不是直接把文件弄进去")

  • 用户上传(custom):PUT /api/agents/{id}/skills/workspace/{name} body {markdown, resources} → 直接写文件到 agent workspace skills/{name}/SKILL.md(+resources/scripts/)→ GET …/workspace 列表(origin=custom|marketplace、version、sizeBytes、hasScripts);DELETE 删除。SKILL.md 必须 YAML front matter(name+description),否则 data 面 FileSystemSkillRepository 加载失败。
  • 启用:definition skills:[{type:"workspace",name:"…"}](或 marketplace 安装后同名启用);运行时 SkillsBundleService.bundleForSession 从 workspace skills/{name}/SKILL.md 生成 bundle,workspace skill 优先于全局 skill。
  • 全局仓库源:SkillRepositoryConfigEntry(agentscope.json 级){type: filesystem|git, path|remoteUrl+branch+skillsRoot+localPath, autoSync} → SkillRepositorySupport 构建 AgentSkillRepository(git 需 agentscope-extensions-skill-git-repository)。Nacos 对接位:git 源或 filesystem 挂载。
  • definition 级 SkillSpec:{type: inline|oci, name, description, instructions, ref}——inline 内嵌 / oci 镜像引用(ref=oci://reg/skill:1 带版本 tag)。

skill 三通道(mermaid 版):

skill 格式约束(体验层必须校验):SKILL.md 必须带 YAML front matter(name + description),否则 SkillUtil.createFrom 抛 The SKILL.md must have a YAML Front Matter…,skill 不注入 prompt。

② 记忆 memory_store_*(回答"存到哪里/有无分布式组件")

  • 内置工具 ManagedMemoryTools:memory_store_list/read/write/edit/delete 等,经 MemoryStoreFilesystem(AbstractFilesystem)挂载到 session 环境 memory-stores/{storeName} 路径(EnvironmentSpecFactory 路由注入 prompt)。
  • 存储 = PostgreSQL(JPA),无文件落盘:源码注释明确 "Memory documents are read/written directly against the MemoryStoreService JPA store — there is no host-disk materialization step"(MemoryMountService.java)。表:cp.memory_stores/cp.memory_versions(control 元数据+版本)、dp.builder_memory/builder_memory_store/builder_memory_version(data 实体+版本)。
  • 无独立分布式组件(本版本):无向量库/Redis/对象存储,单 data + PG 直连;多实例一致性靠共享 PG + 版本表。企业化增强位:向量检索(RAG)、分布式缓存/对象存储(用户 32 文档接线方向)。

记忆读写链路(mermaid 版):

结论:记忆 = 工具层(ManagedMemoryTools)→ 挂载层(MemoryStoreFilesystem)→ JPA 直连 PG;版本化在 memory_versions/builder_memory_version(记忆蒸馏/回滚的落点)。

③ 任务分发(回答"turn 是否转 task、是否要 RocketMQ")

  • turn 确实任务化:control 侧 rt.agent_tasks + rt.execution_attempts(scheduler attempt 语义,非模型调用);data 侧 SessionTurnCommandEntity(turn 命令 JPA 表,status=queued)+ SessionTurnRunner 执行。
  • 官方分发 = PG 中枢 + HTTP/事件,无 MQ:compose 无 RocketMQ/Kafka;POST /turns → control 落库 → data 执行 → ManagedEventOutbox(dp.builder_session_event 出站事件箱)→ ControlPlaneSessionEventMirror 镜像回 control 更新 rt 状态;scheduler 服务(8083)是 channel gateway(外部应用通道配置拉取,非 turn 分发消费者)。
  • Nacos/RocketMQ = 企业化增强位(用户架构方向):官方单体 PG 中枢在规模下的分布式替换(事件总线/任务队列/配置中心),即 32 文档 P 级接线项。

5.5.2 MCP + 审批流运行时实录(2026-10-25 完整证据链) ​

MCP server 准备(本机,端口 3001):

  • 命令:npx @modelcontextprotocol/server-everything streamableHttp(node 进程,监听 0.0.0.0:3001)
  • 探测:POST /mcp + header Accept: application/json, text/event-stream → HTTP 200,serverInfo=mcp-servers/everything 2.0.0,capabilities=tools/prompts/resources/tasks(_mcp_probe3.txt)
  • 容器内可达:GET 返回 len=0(streamable-http 对 GET 无响应属正常;最终以 data 面注册成功为铁证)

agent 更新(踩坑结论):

  • ❌ PUT /api/v1/agents/{id} → 404;PUT /api/v1/agents/{id}/definition → 404
  • ✅ PATCH /api/v1/agents/{id}/definition(前端 updateAgent 同款),body 需含 version(乐观锁,缺则 400 "name and valid version are required")→ HTTP 200,mcpServers 落库,agent.version=3(_agent_def_patch2.txt)

运行时执行链(session fb20f7c1,turn 7016d510,Idempotency-Key=m5-mcp-001):

  1. POST /turns → 202 queued
  2. data 日志:MCP client 'everything' registered successfully → Registered MCP server 'everything' (transport=http) → 工具全量注册 → POST_REASONING | tool_call: name=everything__echo
  3. snapshot:模型调用 1 次(qwen3.8-flash,8239 tokens)→ 生成 everything__echo tool_use(input {"message":"你好MCP"},tool_call_id=call_bebbd07c…)→ required_action(kind=confirmation)挂起,session.runtimeStatus=requires_action,stopReason=tool_confirmation(approvalId=b1a7d579,expiresAt=+1h)
  4. 批准:POST /api/sessions/sess_e6e90137d549/events {"events":[{"type":"user.tool_confirmation","payload":{"tool_use_id":"call_bebbd07c…","allow":true}}]} → HTTP 200 status=approved(source=personal_chat)
  5. snapshot:工具 state=allowed → tool_result Echo: 你好MCP(state=success)→ 模型第 2 次调用(8321 tokens)→ 最终回答"已完成调用 ✅…echo 工具正常工作,原样回显了消息内容" → run.ended(MODEL_STOP)→ turn.completed(_mcp_snap2.json)

审批双路径架构结论:personal chat 场景(managed session)的工具确认由 data 面 HITL(user.tool_confirmation 事件)直接裁决,不落 control rt.approvals;AgentTask/issue 协作场景才走 rt.approvals + POST /api/v1/approvals/{id}/decide(approver=task.AccountableHumanRef)。这解释了 approvals 表为空 + 404 的原因——个人会话审批不在该表。体验层(接入层)复用点:审批 UI = 轮询 snapshot 的 required_actions/stopReason + POST events user.tool_confirmation。

MCP + 审批流运行时闭环(mermaid 版):

turn→task 任务化与分发(mermaid 版):

关键结论:官方 turn→执行 = PG 表做命令/状态中枢 + HTTP/事件回传,compose 无 RocketMQ/Kafka;scheduler 是外部应用通道网关非 turn 分发消费者。Nacos/RocketMQ 属企业化分布式增强位(32 文档接线)。


5.6 M6 文档↔运行时对照收尾(2026-10-25) ​

① 性能/首 token 延迟分布(3 轮采样 + SSE 首 token,会话 e62755c5)

  • turn 提交:冷启动 2137ms / 稳态 98–115ms(_perf_run.txt)
  • 端到端 completed:6736 / 3187 / 3176ms → 稳态 P50≈3.2s(_perf_run.txt,m5-perf-101/102/103)
  • SSE 首 token(首个模型 item.delta):POST 后 3733ms(冷);SSE 首个事件 ~1.5s(_ttft.txt,m5-ttft-001)
  • 事件链 8 类环节(status_running → context_initialized → run.started → input.applied → item.completed(USER) → item.started(model) → item.delta×N → …→ run.ended → turn.completed),首个 delta 前 7 跳;批内生成 37ms(跳间隔 ~6ms)
  • 结论:稳态首 token 端到端 ≈1.5–1.6s、短问答总完成 ≈3.2s;平台自身占比 <15%,延迟大头=模型推理+冷启动 → 体验层优先做长连接复用/SSE 直推/模型网关选路(已同步 33 文档 §7)

② skill session 物化疑点定论

  • 事实:agent workspace SKILL.md=235B(03:04 PUT 后);全部 session workspace=152B(含 03:05/03:16 新建会话)→ 新 session 不拿 agent workspace 实时文件
  • 源码根因:PUT 上传只写 data 面 agent workspace 文件(handlers_agent_extras.go putWorkspaceSkill → putWorkspaceFile);session workspace 由 control 侧 definitionFiles 快照 物化(HarnessAgentBuildService.java:331-332 ManagedDefinitionMaterializer.materialize(workspace, resolved.definitionFiles()))→ PUT 后快照不刷新
  • 定论:官方定义快照与运行时 workspace 不同步(设计缺陷/限制);体验层对策:skill 上传后触发 definition 刷新或按"定义快照为准"语义;物化链 = definitionFiles → 物化 → FileSystemSkillRepository(baseDir=session workspace) → DefinitionStoreSkillRepository 加载(front matter 校验失败即不注入)

③ 新坑记录(补充 §5 问题台账)

  • #11 pwsh 无 BOM 脚本写中文 → GBK 转码乱码:脚本文件 UTF-8 无 BOM 被 pwsh 按 ANSI(GBK) 解析 → JSON body 中文损坏 → POST /turns 400 invalid task input(源码:ShouldBindJSON 失败,service_session_handler.go:526);同一会话手动(命令内联中文)成功、脚本失败 → 定论。对策:脚本一律纯 ASCII(\u 转义)或 UTF-8 BOM
  • #12 PUT skill 上传中文乱码:_skill_put2.txt 返回 200 但落盘 235B 文件 description/正文为 GBK 乱码(同因)→ 体验层上传 UI 必须 UTF-8 显式编码校验
  • #13 新建 managed session 首次 turn 需就绪等待:session 创建后立即 POST turn 偶发 invalid task input(data 面 runtime 初始化未完成);轮询 snapshot 200 也不等于就绪 → 建会话后建议 sleep/重试窗口

④ mermaid 补齐(验证一套沉淀一套):§4.4 M4 端到端链路、§5.5.1 skill 三通道 + 记忆读写链路 三张新增;§5.5.2 MCP+审批 + turn→task 两张既有。

⑤ 49-上线检查清单并入:25-检查清单.md 新增"运行时实证对照(30 台账映射)"节——幂等/SSE续传/审批/工具/Skill版本/记忆CAS/任务账本/模型网关 8 项标注 ✅ 已实证并附锚点;SSO/Nacos/RocketMQ/发布门禁等列 ⏳ 待接线。

M6 结论(2026-10-25):性能多轮分布 ✅(稳态 P50≈3.2s、首 token ≈1.5s、SSE 8 环节);skill 物化疑点定论 ✅(definitionFiles 快照不同步,官方限制);新坑 #11/#12/#13 记录;mermaid 补齐 3 张;49-上线检查清单已并入实证对照。M6 主体完成,剩 49 清单其余项随 P1–P5 接线持续勾选。

5.7 P2 发布动作运行时实证(2026-10-25,definition PATCH + 版本乐观锁) ​

背景:32 §3.6 定论"接入层(HiMarket)= 发布态唯一权威,agentscope 只作执行面",发布动作 = PATCH /api/v1/agents/{id}/definition 组装完整 definition。本次实证把发布动作原语全部坐实。

① definition 结构(GET /api/v1/agents/{id}/definition 200,agent=86a8ba5b)

  • 顶层字段:name/system/description/maxIters(20)/model("openai:qwen3.8-flash")/mcpServers([{name,url}])/skills([{name,type:workspace}])/tools(null)/defaultEnvironmentId/env_d17e35381ab7/defaultVaultIds([])/defaultMemoryStoreIds([])/workspacePath/workspaceId/workspaceVersion(0)/definitionDigest(sha256 快照)/version(3)
  • 全链路字段 = 接入层发布动作的组装模板(32 §3.6 接线动作 1 的落地形态)

② PATCH 语义(重大定论):body 平铺 ManagedDefinitionInput + version({name,version,system,...},不是 {definition:{...}} 嵌套——嵌套会 400 "name and valid version are required");全量替换——未传字段一律清空(实测 mcpServers/model/skills/defaultEnvironmentId 被清空);version 必须=当前值(乐观锁),成功则版本 +1,旧版本再写 → 409 "managed definition version conflict"(源码 agent_catalog_handler.go:655-700 UpdateManagedDefinition → ErrManagedDefinitionConflict)。

③ 中文 body 与回显(坑 #14):PowerShell 发中文 body 必须 UTF-8 字节([IO.File]::ReadAllBytes + Content-Type: application/json; charset=utf-8);且 $r.Content 回显会按本地编码转码成 mojibake(假象,服务器存储是对的)——验证响应必须用 curl.exe -o 文件 读原始字节(本次即用此法确认 system="你是编码助手…" 完好)。原 system 字段曾因首轮 GBK 直传损坏,用备份 _def_full.json 完整恢复成功(version 3→6,内容与修改前一致)。

④ 发布动作链路(mermaid 版,验证一套沉淀一套):

P2 发布动作结论:definition PATCH = 全量替换 + 乐观锁版本,接入层发布动作必须组装完整 definition 并管理版本(409 → 重读重发);中文与回显按 #14 对策(UTF-8 字节 + curl 验证)。模型网关选路(32 §3.1:data 面 openai provider 指向企业网关)+ HiMarket=接入层定论(32 §2)均已沉淀。

5.8 agent 共享授权排查(2026-10-25,官方 main 自身缺陷定论) ​

现象:GET /api/agents/:id/shares → 500(handlers_agent_extras.go listShares)。

根因(官方 main 表名不一致 bug,非环境问题):handler 引用 agent_shares(owner_id/agent_id/grantee_type/grantee_id/tier,agent 专用共享模型),但 migrate.go 实际建表是 resource_shares(resource_type/resource_id/grantee_user_id/permission('RUN'),通用资源共享模型)——两模型语义不同且表名不一致 → 查询不存在表 → 500。官方 main 的 agent 级 shares API 开箱即坏(死代码)。

影响与对策:①"开放给谁用"的 agent 级共享授权官方未落地 → 接入层(HiMarket 市场订阅/授权)承担共享机制;agentscope 侧以 namespace 成员 + publish 权限承接(15 §九.2);②本地 DB 的 cp.resource_shares = 官方迁移产物(本地镜像与 main 一致,排除版本落后);③若需 agent 共享原语:fork 修 handler 表名(agent_shares ↔ resource_shares 对齐)或自定义扩展,记入 HiMarket 改造清单(32 §1.2)。

5.9 skill 内容源运行时实证(2026-10-25,filesystem 源可发现但未注入运行时) ​

目标:验证 32 §3.4 内容寻址机制(Nacos/git/filesystem 内容源 → agentscope 运行时加载)。

做法:本地写 greeting skill(SKILL.md front matter + greeting.py)→ docker cp 到 data 容器 /data/skillrepo-greeting → PATCH definition(version 6→7)加 skillRepositories:[{type:filesystem, path:"/data/skillrepo-greeting"}] + skills 增加 {name:greeting,type:workspace} → 建 session(agentVersion=7)→ turn 验证。

结果(turn completed,4 次模型调用 / 62.997s / 43k tokens,session=6ac9e3bf):

  • ✅ 内容源可发现:模型自主 glob_files **/*greet* 定位 /data/skillrepo-greeting/greeting.py → read_file 读到脚本与 SKILL.md(front matter 完整)
  • ❌ 未注入运行时技能加载器:模型明确答复 "the greeting skill isn't registered in my current skill loader (the only one available there is weather-reporter)"——session workspace skills/ 目录实测只有 weather-reporter
  • shell 执行被权限门拦截(execute state=allowed 但运行时拒绝;PermissionContext BYPASS 下仍受限——独立发现,记入 P3 体验层权限 UI 设计)

源码根因(HarnessAgentBuildService.java):L344 skillRepos = snapshot.skillRepositories() → L477 SkillRepositorySupport.createAll(workspace, skillRepos)(FileSystemSkillRepository 已创建)→ L481-486 skillFilter = SkillFilter.only(workspaceSkillNames(skillRefs))——运行时只放行 definition.skills 引用的技能名;且 session workspace 由 definitionFiles 快照物化(M6 §5.6②),filesystem 源目录不在快照内 → 文件可见但技能未注册。

定论(32 §3.4 接缝坐实):内容源(git/filesystem/Nacos)≠ 直接注入运行时——skill 要真正可被 agent 调用,必须①definition.skills 引用该技能名(skillFilter 放行)+②内容进入 definitionFiles 快照(物化)。Nacos/git 内容源的正确接线 = 接入层发布动作:从内容源拉取 skill → PUT /api/agents/{id}/skills/workspace/{name}(内容进 agent workspace)→ 同步 definition(PATCH definition 让 definitionFiles 快照刷新,规避 M6 物化不同步坑)→ 建 session。此为 P3 体验层/接入层发布动作的关键输入。

5.10 接入层发布动作闭环实证(2026-10-25,✅ 技能真正进入运行时) ​

目标:把 §5.9 定论落地成可复跑发布动作并验证——对比组:§5.9 仅挂 filesystem 源(未注册)vs §5.10 走完整发布动作(已注册)。

动作序列(全部成功):

步请求结果
① 上传PUT /api/agents/{id}/skills/workspace/greeting body {markdown:SKILL.md(front matter name=greeting), resources:{"greeting.py":"print('...published via the release action...')"}}200,resourceCount=1,hasScripts=false(脚本识别规则不影响加载)
② 同步PATCH /api/v1/agents/{id}/definition 平铺 body:skills=[weather-reporter, greeting] + skillRepositories=[filesystem:/data/skillrepo-greeting] + version=7version 7→8,definition.skills=[weather-reporter, greeting],digest 更新
③ 建会话POST /api/v1/agent-sessions201,0bce4dcd-…,agentVersion=8
④ 发消息POST /api/v1/agent-sessions/{id}/turns(Idempotency-Key=p2-skill-010)"Please use the greeting skill…"202 queued,turn=5db038e4-…
⑤ 结果轮询 snapshot → run.ended MODEL_STOPturn.completed

核心证据(模型终答原文):"The greeting skill was registered, so I invoked it directly by loading its SKILL.md via load_skill_through_path",且复现输出 "Hello from the greeting skill! This skill was published via the release action." = ①步上传的 greeting.py 内容。技能已进入 session 技能加载器并被模型直接调用(对比 §5.9:模型只能"读文件绕过",loader 里只有 weather-reporter)。

发布动作链路(mermaid):

定论:发布动作闭环成立——PUT workspace → PATCH definition(快照刷新)→ 新 session(物化)→ turn(注册调用)。这正是 32 §3.4 接缝 2 的落地机制:Nacos/git 内容源将来只需把内容物化成 workspace 上传 + definition 引用,即可让任意来源 skill 进入 agentscope 运行时。副产品:模型检测到沙箱无 Python 解释器(command -v 验证),用 shell 复现输出——sandbox 运行时依赖清单(记入 31 手册运行时依赖节,后续镜像固化 python3)。

5.11 Higress AI 网关实证(2026-10-25,接入机制成立,listener 留官方部署路径) ​

目标:P3 模型网关落地——Higress AI 网关承担"模型统一入口+密钥集中+按 model 路由"。

已完成(✅ 全部实证):

  1. 单容器部署:docker run higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest(8080 网关/8443/8001 控制台)+ 控制台初始化管理员(admin/Higress#2026,本机调研实例)。
  2. AI 服务提供者创建成功(核心证据):控制台创建自定义 OpenAI 兼容 provider qwen-tokenplan → 落盘 /data/wasmplugins/ai-proxy.internal.yaml:id: qwen-tokenplan, type: openai, apiTokens: [sk-sp-H.HMXELP…token-plan key], openaiCustomUrl: https://token-plan.maas.qianwenaiapi.com/compatible-mode/v1 + matchRules llm-qwen-tokenplan.internal.dns——厂商 key 集中落网关配置、自定义兼容端点、模型路由匹配机制全部成立。
  3. 配置存储机制确认:allinone 内置 K8s 兼容 apiserver(https://127.0.0.1:18443,匿名可访问),CRD 文件式存储于 /data/<kind>/;AI 路由 = configmaps ai-route-*.yaml(modelPredicates 匹配模型名 → upstreams provider)。

未完成(❌ 明确记录):默认 Gateway/listener 未生效——envoy 无 8080 监听。根因=手动 docker run 未走官方 curl https://higress.cn/ai-gateway/install.sh | bash 初始化流程(官方脚本在正常路径下创建默认 Gateway,含容器初始化/交互录入 key;本机无可用 bash(WSL 无发行版),脚本不可直接执行)。已尝试:API 创建 GatewayClass(higress.io/gateway-controller)+ Gateway(higress-gateway,8080/8443 listener)→ CRD 创建成功但 controller 未下发 listener(重启容器无效)——不再深挖,此环节留 31 手册:正式部署/重建用官方 install.sh(Linux/CI 有 bash 环境)一步到位。

定论:Higress 模型网关接入机制已验证成立(provider/密钥/路由三要素落盘);默认网关启动属部署环境问题非平台缺陷。P3 模型网关闭环 = 官方部署路径(31 手册补)+ 切 agentscope data 面 base-url 指向 Higress AI 端点。

5.12 用户场景① 最简单 chat 闭环实证(2026-10-25,✅ 历史会话保存/恢复) ​

场景(用户场景推演①):最简单 chat——历史会话保存/恢复、执行资源共享、无落盘。

动作(agent 86a8ba5b version=8,新 session ace1c61d-21f1-4646-9551-46e5bcf31c00):

步请求结果
① 建会话POST /api/v1/agent-sessions201,runtimeKind=managed
② Turn1POST .../turns(Idempotency-Key=p3-chat-001)"记住:我的名字是 Alice…"202 queued,turn=142b6afb → run.ended
③ Turn2POST .../turns(p3-chat-002)"What is my name that I told you before?"202 queued → run.ended
④ 验证GET snapshotsnap2 items 含 Turn1+Turn2 全量事件;Turn2 ASSISTANT = "Alice." ✅

核心证据:①历史保存——snapshot 按 session 累积事件(items 含两个 turn 的 USER/ASSISTANT 完整消息);②历史恢复——Turn2 模型答出 "Alice."(同 session 多轮上下文延续,无需外部状态);③执行资源共享——同一 session 共享上下文/workspace;④附带洞察——Turn1 模型主动提示"未写入 long-term memory,需要可用 memory 工具保存"——会话级记忆(turns 上下文)与长期记忆(memory_stores)分界清晰,正好承接场景①(无落盘、会话内)与场景⑦(记忆蒸馏)的设计。

chat 会话生命周期(mermaid):

结论:场景① 全链路原生支持(无自研组件)——session 即历史容器,多轮 turns 上下文自动累积,执行资源共享;"无落盘"语义=会话数据存 PG(cp 库),对外仅按 session 访问。此为 P3 体验层 Chat 最小闭环的运行时基础。

5.13 用户场景② chat+可选工具 闭环实证(2026-10-25,✅ 中间产物回填会话) ​

场景:chat + 可选工具(联网搜索等),中间产物可放数据库/会话。

动作(agent 86a8ba5b v8,新 session 000eb84b-af35-47d5-ad09-6cc6337ebff5,Idempotency-Key=p3-chat-010):

  1. Turn:"Use the MCP tool everything__echo to echo the text: scenario2-with-tool…" → 202 queued(turn=d0d2c6c3)
  2. 模型自主选工具:ASSISTANT tool_use everything__echo {message: scenario2-with-tool}(state=allowed)
  3. 工具执行成功:TOOL tool_result Echo: scenario2-with-tool(state=success)
  4. 模型终答(final_output):"the tool ran… It took my input text scenario2-with-tool and returned it prefixed with Echo:"
  5. turn.completed + run.ended MODEL_STOP;usage model_calls=2、totalTokens 17971(cachedTokens 14336=会话上下文缓存复用)

核心证据:中间产物持久化——tool_result + tool.updated(tools[])完整落在 session 事件流,snapshot 全量可查("中间产物放会话"✅);工具结果被模型终答引用(工具闭环✅);usage 精确计量工具链 token 消耗(成本基础✅)。差异记录:本次 echo 未经审批直接执行(M5 时挂起需 HITL 批准)——同一工具不同轮次策略行为不同,待 32 §4 接缝表补充确认(疑似工具策略/权限配置差异,非缺陷)。

chat+工具 生命周期(mermaid):

结论:场景② 原生支持——chat 中按需挂工具、工具中间产物回填会话事件流(即"放数据库/会话")、用量可计量。P3 体验层"聊天中调工具"闭环成立。

5.14 用户场景③ 开放技能包 闭环实证(2026-10-25,✅ 脚本→workspace→状态外置) ​

场景:开放技能包(脚本→workspace→数据隔离→操作文件→状态外置)。

动作(agent 86a8ba5b v8,session 79ddd61d-a3f8-46cf-8a83-ab1d3e08c027,Idempotency-Key=p3-chat-020;Turn="调用 greeting skill + 写 state.txt 再读回"):

步工具结果
① skill 加载load_skill_through_path(skillId=greeting_filesystem-…_skills, path=SKILL.md)✅ 返回 SKILL.md + Files root=/data/workspaces/sessions/{sidHash}/.skills-cache/{sid}/filesystem-{…}_skills/greeting
② 写文件(状态外置)write_file(state.txt, "state-externalized")✅ "Written to state.txt"
③ 执行脚本execute(greeting.py)python3 not found(沙箱无 python3)→ 模型自适配用 perl 复现:输出 "Hello from the greeting skill! This skill was published via the release action."(exit 0)✅
④ 读回read_file(state.txt)✅ "state-externalized"
⑤ 字节级自验证od -c state.txt✅ 18 bytes state-externalized 无尾随换行
⑥ 终答final_output✅ 汇总两任务结果(含对 skill 内容/状态文件的完整描述)

核心证据:

  • workspace 数据隔离:session 级目录 /data/workspaces/sessions/{sidHash}/{sid}/(state.txt 落此);skill 物化于 .skills-cache/{sid}/——每 session 独立空间,天然隔离;
  • 状态外置成立:write→read→od 三级验证,中间状态/结果存 workspace 文件而非会话文本;
  • 发布动作闭环再强化:§5.9 时 execute 仅 state=allowed 未执行;现在(发布动作后)execute 真正执行成功——skill 内容源经发布动作后不仅注册(§5.10)还可执行;
  • usage:model_calls=7(多轮工具循环)、totalTokens 74612、cachedTokens 60160——上下文缓存复用显著(长工具链成本可控)。

缺口记录:沙箱无 python3(greeting.py 未能直接运行,模型用 perl 复现语义等价输出)→ 31 手册运行时依赖清单补 python3(或 skill 发布规范约束解释器声明)。

开放技能包 生命周期(mermaid):

结论:场景③ 原生支持——脚本技能可加载/执行、workspace 每 session 数据隔离、文件读写+状态外置完整成立;唯一缺口=沙箱解释器依赖(31 手册补 python3)。P3 开放技能包闭环成立。

5.15 用户场景④ 个人工作助手 闭环实证(2026-10-25,✅ 独享运行态+并行隔离) ​

场景:个人工作助手——独享运行态、闲置回收/复用恢复。

动作(agent 86a8ba5b v8,并行双 session A=3f54ba0c-f50d-4628-8462-be4662c86bde、B=1b226cb4-eebb-473f-a184-c04a8c0df7db):

步AB
① 建 session201(独立 runtimeKind=managed)201(独立)
② Turn1 记名"记住我是 Alice"(p4-a-001)"记住我是 Bob"(p4-b-001)
③ 完成run.ended → runtimeStatus=idle(闲置)run.ended → idle
④ Turn2 问名"What is my name?"(p4-a-002)→ 终答 "Alice"→ 终答 "Bob"
⑤ 复用恢复idle 后再次 turn 正常执行(复用恢复)同

核心证据:

  • 独享运行态成立:双 session 并行各自记名,互问互不串扰(A=Alice / B=Bob)——每 session 独立上下文/workspace/run 生命周期;
  • 闲置回收/复用恢复:每个 session run.ended 后 runtimeStatus=idle(闲置态),再次发 turn 自动恢复执行(Turn1→Turn2 跨闲置复用)——个人助理"挂起/唤醒"语义原生支持;
  • 多用户/多实例承载:每用户=每 session 独立空间(P1 §九.2 namespace 隔离之上再加 session 粒度隔离),百炼"会话"管理形态的运行时基础。

个人工作助手 独享运行态(mermaid):

结论:场景④ 原生支持——每 session 独享运行态(上下文/workspace/生命周期隔离)、闲置后可复用恢复;个人工作助手(多实例并行、各自独立、随时挂起唤醒)闭环成立。此为接入层"个人应用/会话管理"产品化的运行时基座。


5.16 QwenPaw 容器化 + ACP 拉起 opencode 实机闭环(2026-10-25,✅ 数字分身→编码执行引擎链路跑通) ​

目标:把 34 篇路线 A(QwenPaw 个人实例经 ACP 拉起 opencode,人控制/指导)从设计落到实机,顺带坐实 QwenPaw 作为员工数字分身的容器形态(模型通路 + 会话入口 + 委托编码交付)。

5.16.1 镜像获取踩坑链(国内可用镜像源) ​

尝试结果
docker.io/agentscope/qwenpaw:latest 直连443 超时(Docker Desktop 无代理,IPv6 直连不通)
ACR 亚太 agentscope-registry.ap-southeast-1.cr.aliyuncs.com/agentscope/qwenpawpull access denied(README 声称国内 ACR 可用,未 login)
daocloud 镜像站EOF
docker.1panel.live/agentscope/qwenpaw:latest✅ 拉取成功,docker tag 为 agentscope/qwenpaw:latest

启动形态:docker run -d --name qwenpaw --init --restart unless-stopped -p 127.0.0.1:8088:8088 + 三卷(qwenpaw-data→/app/working、qwenpaw-secrets→/app/working.secret、qwenpaw-backups→/app/working.backups)+ -e OPENAI_BASE_URL=https://token-plan.maas.qianwenaiapi.com/compatible-mode/v1 + -e OPENAI_API_KEY=<完整 key> + -e QWENPAW_DISABLED_CHANNELS=imessage。初始化完成(8 个 MD 文件 + 16 skills),supervisord 拉 xvfb/xfce4/dbus/app 全 RUNNING,http://127.0.0.1:8088/ 200。

5.16.2 模型配置两大坑(token-plan 通路) ​

  1. 内置 aliyun-tokenplan provider 指向 token-plan.cn-beijing.maas.aliyuncs.com,与我们的 key 域名(token-plan.maas.qianwenaiapi.com)不匹配 → 401 invalid_api_key;
  2. key 必须用 .env 完整值(sk-sp-H.HMXELP.4cCS.MEUCI…),记忆/截断版不可用 → 401。

解法(自定义 provider):qwenpaw models add-provider tokenplan -n 'TokenPlan' -u 'https://token-plan.maas.qianwenaiapi.com/compatible-mode/v1' + add-model tokenplan -m qwen3.8-flash + 双行管道 stdin 喂 config-key(第一行空行保持 base_url、第二行 key——自定义 provider 交互顺序是 base_url→key)→ ✓ TokenPlan — API Key: sk-s…0;active slot 由 docker cp 改写 /app/working.secret/providers/active_model.json = {"provider_id":"tokenplan","model":"qwen3.8-flash"}(docker exec printf 嵌套引号在 PowerShell 下 Syntax error,改 docker cp 方案)。

冒烟成功(headless 任务):qwenpaw task -i '用一句话回答:你现在用的什么模型?' --output-dir /tmp/qwp_task4 --timeout 120 → {"status":"success","elapsed_seconds":5.08,"response":"我用的是 Qwen3.8 Flash。"},builder 日志 model=tokenplan/qwen3.8-flash tools=0。注意 -m 参数在 task 里不覆盖 active slot,须改 active_model.json。

5.16.3 容器内 opencode 就位 + ACP 委托链路启用 ​

  • 容器内 npm install -g opencode-ai → opencode 1.19.4;D:\build\opencode-runner\opencode.json(tokenplan provider+key+qwen3.8-flash 默认模型)→ /root/.config/opencode/opencode.json;CLI 确认 acp / run / serve / attach / mcp / agent / providers / export 全支持;
  • 生效配置是工作区 agent.json,不是 /app/working/config.json:delegate_external_agent 工具在 workspaces/default/agent.json 的 tools.builtin_tools.delegate_external_agent.enabled 控制;内置 acp.agents 四 runner 全 enabled+trusted(opencode=opencode acp、qwen_code、claude_code、codex);
  • 实测中模型自身发现工具禁用后自主编辑 agent.json 启用并完成委托(无需平台干预),验证了"agent 自治 + 工具注册按会话构建"的运行时事实:新启用需新会话才进工具 schema。

5.16.4 ACP delegate 实机闭环(核心证据,session=delegate-demo-02) ​

链路:POST /api/console/chat(console channel / user_id=alice / session_id=delegate-demo-02,SSE 流式)→ QwenPaw agent(tokenplan/qwen3.8-flash,cache hit ~94%)→ delegate_external_agent(action=list) 列出 4 runners → (action=start, runner=opencode, cwd=/app/working/workspaces/default/projects/delegate-demo, message=修改 index.html 补一句) → opencode ACP 子进程自主 read→edit 完成 → (action=close) → 会话关闭。

产物验证:D:\build\opencode-out\delegate-demo\index.html(302B,<p>基于开源软件打造企业智能体平台。</p> + <p>支持统一入口触达个人数字分身。</p>,opencode 自行 read→edit,未用 execute_shell_command 代劳)。同会话内模型还自主复核文件内容并在终答列出。

附带发现(供接入层规划):qwenpaw hub = 多用户控制面子命令(--init-admin USERNAME / --force-public),天然对位"统一管理员工数字分身";qwenpaw acp 让 QwenPaw 自身作为 ACP Server 被外部客户端驱动;原生 channels 支持 console/feishu/dingtalk/wecom/qq/telegram/slack/matrix/voice/sip/wechat(默认仅 console);HTTP 发消息端点为 POST /api/console/chat(注意前缀 /api,/console/chat 会 405);/openapi.json 未暴露。


6. 关键 ID 与产物(可复跑) ​

对象ID
agent86a8ba5b-53e2-41b3-be27-acaf310cf27c(active,model=openai:qwen3.8-flash)
binding50cabcc6-5fef-5768-94e1-6e4d7af05b83
session23c43553-16a5-5dfb-8efb-b8a25929f3d3
turn(乱码轮)462d9a05-5039-4921-a207-c800662c264f(completed)
turn(中文轮)e77b177f-52e8-49a9-a7fa-4d38f28cb0d2(completed)
environmentenv_d17e35381ab7
namespacepersonal-2fc9756ccf936edc09a1(tenant=default)
镜像as-dataplane:local-openai(本地)、官方 sca-registry.cn-hangzhou.cr.aliyuncs.com/agentscope/as-*:2.1.0-BETA1
源码agentscope-java official-main(d04529e9);构建副本 D:\build\agentscope-java
场景① session(§5.12)ace1c61d-21f1-4646-9551-46e5bcf31c00(turn1=142b6afb / turn2 恢复答 "Alice.";幂等键 p3-chat-001/002)
场景② session(§5.13)000eb84b-af35-47d5-ad09-6cc6337ebff5(turn=d0d2c6c3;everything__echo tool_use=call_414037ef…;幂等键 p3-chat-010)
场景③ session(§5.14)79ddd61d-a3f8-46cf-8a83-ab1d3e08c027(turn=089dcbf7;greeting skill + state.txt;幂等键 p3-chat-020)
场景④ session(§5.15)A=3f54ba0c-f50d-4628-8462-be4662c86bde(Alice)/ B=1b226cb4-eebb-473f-a184-c04a8c0df7db(Bob);幂等键 p4-a-00x / p4-b-00x
QwenPaw 容器(§5.16)名称 qwenpaw(镜像 agentscope/qwenpaw:latest ← docker.1panel.live 拉取后 tag);dashboard 127.0.0.1:8088;三卷 qwenpaw-data/secrets/backups;QWENPAW_DISABLED_CHANNELS=imessage
QwenPaw 模型(§5.16)自定义 provider tokenplan(base_url=token-plan.maas.qianwenaiapi.com/compatible-mode/v1);active slot /app/working.secret/providers/active_model.json={provider_id:tokenplan, model:qwen3.8-flash}
opencode 容器内(§5.16)1.19.4(npm -g opencode-ai);配置 /root/.config/opencode/opencode.json(tokenplan+qwen3.8-flash);runner 定义 acp.agents.opencode(opencode acp,enabled+trusted)
delegate 会话(§5.16)chat=d9e58f9e-59bc-472f-bf54-d4dbe4f6e354(session_id=delegate-demo-01)/ delegate-demo-02(ACP 闭环);工具 delegate_external_agent(list/start/message/respond/close)在 workspaces/default/agent.json enabled
delegate 产物容器内 /app/working/workspaces/default/projects/delegate-demo/index.html;宿主机 D:\build\opencode-out\delegate-demo\index.html(302B)

7. 架构结论沉淀(模型接入层) ​

  • 模型是 agent 级属性,不是 dataplane 级:官方 HarnessAgentBuildService 读 snapshot.model() → HarnessAgent.Builder.model(String) → ModelRegistry.resolve(modelId)(HarnessAgent.java:1722-1723),按 provider:model 前缀匹配 ModelProvider.supports()(openai:.+ / dashscope:.+ / deepseek:.+…)。
  • 多厂商是官方一等公民:openai 扩展 jar 内置 deepseek/glm/kimi/minimax 兼容 provider(compat/deepseek 等源码存在)。
  • 厂商差异收敛在两处:①镜像打包依赖(对应 provider 扩展 jar);②凭据 env(DASHSCOPE_API_KEY/OPENAI_API_KEY/DEEPSEEK_API_KEY)。
  • 企业级多厂商统一:架模型网关(一个 base-url + 一个网关 key,model 名路由)——本次 token-plan 网关即实例;dataplane 只配 openai provider 指向网关。

8. 后续里程碑(M5/M6 与用户待接线项) ​

  • [x] M5 已完成:幂等同键同体、SSE 事件流+cursor 续传、工具调用、MCP 运行时全链路、审批流运行时(personal HITL + AgentTask collaboration 双路径)(见 §5.5 / §5.5.1)。
  • [x] M5 续做(2026-10-25 完成):MCP 运行时验证(真实 MCP server everything + 工具注入 + 模型自主调用 + 执行回填);审批流运行时验证(tool_confirmation 触发 + user.tool_confirmation 批准 + 执行继续)。
  • [ ] M5 遗留:控制台 UI Chat 路径问题(台账 #9/#10,用户拍板搁置,体验层接管);skill 运行时接线(definition skills 字段 + SkillRepositoryConfigEntry filesystem/git 源,能力面已确认,待配真实 skill 仓库)。
  • [ ] 环境重建交接:已产出《31-环境重建与自动化部署手册》(M1→M4 全命令复跑 + 坑速查 + 验收清单),新环境可据此对等继续。
  • [ ] M6 文档↔运行时对照修正:性能/首 token 延迟、SSE 环节数实测(首笔已得:turn 提交 2240ms/轮询 2076ms,见 33-文档 §7)、本台账并入 49-上线检查清单。
  • [x] 架构决策(2026-10-25):不直接开放 agentscope UI,构建统一体验层("接入层"),API 复用 + 体验层自研(混合路线,见 33-文档);官方 UI 缺陷 #9/#10 降级为非阻塞项。
  • [x] P3 体验层运行时实证(2026-10-25 完成):场景①最简 chat(§5.12)、②chat+工具(§5.13)、③开放技能包(§5.14)、④个人工作助手独享运行态(§5.15)四链路全部原生支持并沉淀 mermaid。体验层 Chat/工具/技能包/个人会话 运行时基座齐备。
  • [x] P3 模型网关收敛(2026-10-25):Higress AI 网关机制实证成立(§5.11),listener 部署留官方 install.sh(31 手册);自研模型代理/One API 已否决。
  • [ ] HiMarket 二开追百炼(用户决策 2026-10-25,P2 接线暂缓):二开方向与差距清单已沉淀(P3 交付文档 §4 / 32 文档待并入);元数据编排(skill/mcp/agent 元信息→HiMarket、skill 内容→Nacos、执行→agentscope-service API 组织)为核心关注点。
  • [x] QwenPaw 容器化 + opencode 调用链路(2026-10-25 闭环):qwenpaw 容器形态跑通(镜像 1panel 源、tokenplan 通路、headless task 冒烟 5.08s),ACP delegate 拉起 opencode 实机闭环(§5.16,session=delegate-demo-02,产物 D:\build\opencode-out\delegate-demo\index.html)。QwenPaw-Data(Neo4j 知识图谱)确认独立,不在主线。
  • [ ] 用户架构议题:模型网关层设计(见 §7,待独立章节展开)。

结论要点:M4 端到端链路(API 侧)完整闭环——Login→Environment→Agent(managed, model=openai:qwen3.8-flash)→Session→Turn→模型回答 全部运行时坐实,三轮 turn 均 completed(含中文与"OK"验证)。控制台图形界面 Chat 路径存在官方 main 运行时缺陷(UI 会话未进执行管线、历史会话读空、events 403),API 侧不受影响,已记台账 #9/#10 待 M5 排查。

把 AI 工程讲到既懂也会用