Ignis 平台全景
**Ignis**(D:/wks/rust/ignis,Rust workspace):不是"让 agent 更会聊天",而是把 agent 放回工程系统—— > 服务有边界、任务有状态、输出有 schema、依赖有图、运行时有隔离、平台有部署链路。 两分分工: - **Ignis**(开发者/框架侧):project/service 开发、Wasm HTTP service、manifest 校验、SDK、运行时、TaskPlan 框架 - **IgnisCloud**(平台侧):项目/服务/版本/部署/节点激活、服务发现、agent 容器、对象存储、SQLite 备份、job/schedule、计费 为什么分布式多 agent:单 agent 上下文有限、易"上下文污染";复杂任务分治——重点是**边界**而非机器数。
```text ignis/ ├── crates/ │ ├── agent-service/ # 核心:agent 任务服务(单文件 main.rs ~1100 行) │ ├── taskplan/ # 多 agent DAG 编排(校验/调度/输出绑定) │ ├── ignis-cli / ignis-manifest / ignis-runtime / ignis-platform-host / ignis-sdk ├── examples/math-proof-lab/ # 6 agent 协作的定理证明应用 ├── skills/ # ignis / ignis-login 两个 agent 技能 └── docs/agent-service-implementation.md # 1281 行中文设计文档 ```
`ignis.hcl` 描述 project/listeners/exposes/services/jobs/schedules;三类服务: - **http**:编译为 `wasm32-wasip2` 的 `wasi:http` 组件 - **frontend**:静态产物 + SPA fallback - **agent**:平台内置容器(默认 Codex runtime,支持 OpenCode)——**agent 是服务体系的一等公民,而非外挂** 服务发现:项目内 `.svc` 内部地址(如 `http://api.svc`)与系统服务 `__ignis.svc`(`GET __ignis.svc/v1/services` 可列出全部 agent 及其 `agent_description`)。
agent-service 源码解读
**倒置的架构(Agent-as-a-Service)**:不自建 LLM 客户端,把 Codex/OpenCode CLI 当一次性 runtime——每个任务 spawn 一次子进程: ```rust // crates/agent-service/src/main.rs:733(节选) let mut command = match state.config.runtime { AgentRuntime::Codex => { let mut command = Command::new(&state.config.codex_bin); command.arg("exec").arg("--json") .arg("--skip-git-repo-check") .arg("--dangerously-bypass-approvals-and-sandbox"); if let Some(model) = state.config.codex_model.as_deref() { command.arg("--model").arg(model); } command.arg("-C").arg(&state.config.workspace_dir) .arg(state.config.system_prompt.clone()); command } AgentRuntime::Opencode => { /* opencode run --format json ... */ } }; command.current_dir(&state.config.workspace_dir).kill_on_drop(true); ``` 超时看护(`wait_for_codex`):`tokio::time::timeout` 击杀超时进程 → 标记 `CODEX_TIMEOUT`;进程提前退出未提交 → 标记 `CODEX_EXITED_WITHOUT_SUBMIT` 兜底;任务完成后**串行续跑**队列下一个任务。 价值:用进程边界换隔离与确定性,天然防"agent 循环贪多任务"。
"循环逻辑"写在系统提示词里(`default_system_prompt`,main.rs:239): ```text 你是 agent-service 的任务执行 Agent。你必须遵守以下流程: 1. 先调用 get_task 获取任务。 2. 如果 get_task 返回 task_id = null,说明当前没有任务,直接结束。 3. 如果拿到任务,只处理这一个任务。 10. 如果 submit_task 返回 ok=false 或工具错误,必须根据错误信息修正 result 并再次调用 submit_task。 11. 不要因为一次 schema 校验失败就结束任务;持续修正并重试, 直到 submit_task 成功或运行超时。 14. 本次 agent runtime 只服务当前一个任务,不能循环处理队列。 ``` 角色文件 `AGENTS.md` 追加进提示词(**拒绝 symlink 防提示注入**);技能放 `services/<agent>/skills/<skill>/SKILL.md`。
工具用 JSON Schema 静态定义,经标准 MCP(JSON-RPC over HTTP)分发——给 agent 的工具只有 3 个: ```rust // main.rs:535(节选) "get_task" // 从 SQLite 队列原子领取一个 queued 任务(CAS 置 running) "submit_task" // 提交最终 JSON,服务端 schema 校验 + 回调 + 落库 "spawn_task_plan" // coordinator 动态生成子任务 DAG(经 tool_callback_url 转发) ``` MCP 路由(initialize / tools/list / tools/call)+ `isError` 语义:结果 `ok=false` 时以工具错误形式回给 agent。
**Schema 驱动的结果契约 + 校验即重试**(本页最值得抄的设计): ```rust // main.rs:649(节选) let schema: Value = serde_json::from_str(&task.task_result_json_schema)?; if let Err(error) = validate_json_with_schema(&schema, &args.result) { warn!(task_id = task.id, %error, "submit_task failed schema validation; keeping task running for retry"); return Ok(tool_error("SCHEMA_VALIDATION_FAILED", &format!("result does not match task_result_json_schema: {error}"))); } ``` 校验失败**不把任务置 failed**,而是作为 MCP 工具错误回给 agent 让它修正重交——把"结构化输出"从 prompt 恳求变成协议强制。
TaskPlan:多 Agent DAG 编排
TaskPlan 把协作变成**可执行数据结构**(crates/taskplan): | 结构 | 字段 | 说明 | |------|------|------| | TaskPlan | id / root_task_id / tasks / dependencies | 任务 DAG | | TaskSpec | id / agent_service / prompt / input / output_schema | 单任务契约 | | TaskDependency | upstream → downstream | 依赖边 | | OutputBinding | JSON Pointer 绑定 | 上下游输出注入 | | TaskState | queued / running / waiting_child_plan / succeeded / failed / cancelled | 状态机 | 一句话:**状态在数据库里、依赖在 TaskPlan 里、输出用 schema 验证**。
taskplan crate 提供四个核心函数: - `validate_plan`:含拓扑排序环检测 - `ready_task_ids`:就绪任务调度(前驱已成功) - `apply_output_bindings`:用 **RFC 6901 JSON Pointer** 把上游输出写进下游 input - `validate_task_output`:按 output_schema 校验
**coordinator 挂起/恢复**:coordinator 调 `spawn_task_plan` 后进入 `waiting_child_plan` 挂起态,子计划全部完成后再被 continuation prompt 唤醒汇总。 铁律:**agent 不能改写已有计划,动态扩展只能通过 append-only 的 child plan**——可审计、可定位失败("计划从上下文里的自然语言,变成数据库里的可执行计划")。
实战示例与快速上手
`examples/math-proof-lab`:六个专业 agent 协作(每个 agent = AGENTS.md 角色提示词 + ignis.hcl 声明): | agent | 职责 | |-------|------| | orchestrator | 主控拆解调度 | | literature | 文献/知识检索 | | formal-verifier | Lean/Coq/Isabelle 形式化验证 | | curriculum | 受众认知水位映射 | | pedagogy | 费曼式降维讲解 | | rigor-critic | 严谨性审稿驳回 | orchestrator 的 AGENTS.md 里甚至有"必须用 python3 json.dumps 构造 JSON-RPC、不许 shell 拼 JSON"这类实战提示词细节。
典型多 agent 工作流(7 步): ```text 1. 前端提交 → api 创建任务 2. api 从 __ignis.svc/v1/services 拿 agent 列表 3. available_agents 注入 orchestrator 提示词 4. orchestrator spawn_task_plan 提交子计划(经 callback 给 api) 5. api 作为 TaskPlan executor:校验/记录/按依赖分发给 research/reviewer 等 6. 各 agent submit_task(结构化 JSON),api 做 output binding 7. 子计划完成 → 父任务恢复汇总输出 ``` 关键分工:**coordinator 负责表达计划,executor 负责调度记录**;agent 按能力目录(agent_description)被动态选中,而非固定流水线。
```bash curl --proto '=https' --tlsv1.2 -LsSf https://igniscloud.dev/i.sh | sh ignis login ignis project create hello-project ignis service new --service api --kind http --path services/api ignis service new --service web --kind frontend --path services/web ignis service check/build/publish/deploy --service api # 创建一个 agent 服务(OpenCode runtime) ignis service new --service research-agent --kind agent \ --runtime opencode --path services/research-agent ``` agent 服务需在 ignis.hcl 写 `agent_description`(进服务发现,供 coordinator 分派);`agent_memory = "session" | "none"` 控制记忆模式(orchestrator 用 session,专家 agent 用 none)。
参考
     igniscloud/ignis 
     IgnisCloud