使用项目经验与有限修订
Evolution 把真实工作经历整理成项目级 project-experience Skill,供后续 Agent 按需加载。还可以显式开放少量 prompt 或配置字段,让维护流程提出并发布修订。本文说明如何启用、查看产物,以及在 Python 宿主里绑定维护资源。
前提:已完成快速开始,理解 Skill 的发现与加载。开启这些机制会产生独立模型请求和本地文件写入;生成出文件表示机制完成了一次工作,不代表效果已经提升。
先只沉淀项目经验
在 workspace 保存 agent.yaml:
name: project-worker
model: deepseek/deepseek-flash
system: |
帮助用户完成项目工作,需要项目惯例时按需加载 Skill。
区分实际结果与猜测,保留用户明确指出的修正。
permissions:
workspace: .
skills:
enabled: true
evolution:
enabled: true
maintenance:
idle_seconds: 300uv run iris chat agent.yaml完成一些有具体反馈的工作后,保持宿主空闲。维护会读取合格 Run 的已提交材料,用一次独立模型请求决定是否更新 .agents/skills/project-experience/SKILL.md。没有新材料时结果为 empty;有材料但没有值得改动的经验时可以是 no_change。不是每次聊天都会新增一条经验。
首次生成的 Skill 由新 runner 在构造时发现;已经发现这个 Skill 的 runner 在下一次 load_skill 时读取新正文。已有消息中的旧正文保持原样。查看文件、确认 catalog 出现名称、确认模型实际调用加载工具,是三种不同的观察结果。
开放明确的修订范围
以下是上面配置的 evolution 段替换示例:
evolution:
enabled: true
prompt_targets: [project_skill_update]
config_targets: [system]prompt_targets 和 config_targets 默认都是空集合;只开启 Evolution 不会顺带开放 prompt/config 修改。经验整理发现有原文依据的机制问题时,可以提交开放目标的修订项;宿主也能明确提交一个请求。一次修订只发布一个 prompt 文件,或者在唯一主 YAML 中修改指定叶字段。
发布前会检查候选能否按对应领域契约使用:prompt 用代表变量渲染,配置用原 YAML 路径重新解析。这里验证的是结构与可用性,不包含自动效果评估。配置发布只影响新 runner;已存在 runner 的新会话、follow-up 和 Goal 续跑继续使用构造时配置。
Python 宿主的完整装配
这个脚本使用上面的 agent.yaml,需要先开放 config_targets: [system]。它还兼容在同一配置中开启 memory.enabled 和 memory.generation.enabled:两类维护共享宿主空闲状态,使用各自的服务和工作位置。
在 agent.yaml 同目录保存为 run_evolution.py:
import asyncio
from pathlib import Path
from iris import init_config
from iris.agents import load_agent_config
from iris.evolution import RevisionRequest, RevisionTarget
from iris.harness import (
AgentRunner,
MaintenanceCoordinator,
MemoryMaintenanceBinding,
build_project_evolution_binding,
)
from iris.lifecycle import AgentRunRequest
from iris.memory import build_memory_service_from_config, resolve_memory_path
from iris.prompts import PromptSource
from iris.providers import create_provider_client
async def main() -> None:
init_config()
config_path = Path("agent.yaml").resolve()
config = load_agent_config(config_path)
workspace = (config_path.parent / config.permissions.workspace).resolve()
prompts = PromptSource.initialize(workspace, config.prompts.root)
provider = create_provider_client(
config.to_model_route(),
api_style=config.model.api_style,
base_url=config.model.base_url,
timeout=config.model.timeout,
)
memory = build_memory_service_from_config(
config.memory,
workspace,
prompt_source=prompts,
overview_provider=provider,
overview_model=config.model.name,
)
evolution = build_project_evolution_binding(
config,
workspace_root=workspace,
prompt_source=prompts,
provider=provider,
config_path=config_path,
)
assert evolution is not None
runner = AgentRunner.from_config(
config,
config_path=config_path,
provider=provider,
memory_service=memory,
prompt_source=prompts,
)
coordinator = MaintenanceCoordinator(idle_seconds=config.maintenance.idle_seconds)
memory_binding = (
MemoryMaintenanceBinding(
service=memory,
database_path=resolve_memory_path(config.memory.path, workspace),
namespace=config.memory.write_namespace,
)
if memory is not None and config.memory.generation.enabled
else None
)
runner.bind_maintenance(coordinator, memory=memory_binding, evolution=evolution)
try:
result = await runner.start(
AgentRunRequest(input="本项目的回答请先给结论,再给支持它的事实。")
)
print(result.run.stop_reason)
experience = await coordinator.request_project_experience(evolution)
print(experience.status, experience.reason, experience.effect)
revision = await coordinator.request_revision(
evolution,
RevisionRequest(
description="将 system 调整为先给结论,再说明事实依据,保留现有职责。",
targets=(RevisionTarget(kind="config", name="system"),),
),
)
print(revision.status, revision.reason, revision.effect)
finally:
await coordinator.aclose()
await runner.aclose()
asyncio.run(main())uv run python run_evolution.py这个例子会把明确的修订请求交给模型,可能修改主 agent.yaml 的 system 字段;运行后检查打印的 status、effect 和文件实际差异。模型也可以选择 no_change,因此不能承诺固定改写内容。YAML 发布会重新序列化文件,原注释和排版不会保留。
request_project_experience() 跳过普通空闲计时,仍等待前台退出、合格来源和项目锁;它整理经验,不代替显式修订请求。request_revision() 等待本次持久请求自己的结果,不会误把另一次维护完成当成本次完成。
宿主何时可以关闭
一个宿主可以让多个 runner 绑定同一个协调器;同一数据库与 namespace 使用同一记忆服务,同一 workspace 使用同一经验服务。任一前台运行进入时都会撤销正在进行的后台生成;已开始的短 IO 要排空后才释放资源。
结束前先停止或等待前台运行;上例在所有调用返回后关闭协调器,再关闭 runner。协调器停止派发并等待真实 IO 收尾,runner 解除借用关系。协调器不替宿主关闭注入的 lifecycle reader、服务或观测资源。若只移除一项资源,先关闭借用它的 runner,再调用 unbind_memory() 或 unbind_evolution()。
经验材料、进度和发布历史位于 .iris/evolution/evolution.db;它们用于维护推进,不提供记忆 Search/Fetch。模型读回的记忆和 Skill 正文不会再次被复制为新事实,后续真实反馈仍能成为材料。对外使用的经验产物是 Skill,修订产物是明确开放的文件。历史列表返回摘要,查看正文时按 ID 调用详情接口,见历史查询契约。
