发布时间:2026/6/16 11:58:21
文章目录1. 前言2. 总体流程3. 基础提示词3.1 设置方式3.2 存储位置4. Transformer 链实现4.1 源码入口4.2 反射检测4.3 串行执行4.4 系统提示词中间件4.4.1 WorkspaceContextMiddleware4.4.2 TaskReminderMiddleware4.4.3 PlanModeMiddleware4.4.4 HarnessSkillMiddleware4.4.5 SubagentsMiddleware通过 onReasoning4.5 最终 System Prompt 结构5. 生命周期要点分析AgentScope Harness中System Prompt的组装、注入和生命周期管理机制。1. 前言系统提示词System Prompt是给大模型底层预设的固定指令优先级高于用户每一轮提问相当于提前给AI定好身份、规则、能力边界、输出规范全程生效。在构建HarnessAgent时指定了一个简单的系统提示词HarnessAgentagentHarnessAgent.builder().name(harness-demo).description(HarnessAgent Demo).sysPrompt(你是一个中文 AI 助手).model(model).workspace(workspacePath).maxIters(5).build();在进行对话时可以看到当前AI回复的内容包含了更强大的能力说明AgentScope框架内部对系统提示词进行了增强处理2. 总体流程System Prompt通过Transformer 链逐层组装最终注入到LLM推理的SYSTEM消息中。HarnessAgent.builder().sysPrompt(你是 AI 助手) │ ▼ ReActAgent.sysPrompt ← 存储基础提示词 │ ▼ seedSystemMsg() 被调用每次推理前 │ ▼ applySystemPromptMiddlewares(base, ctx) ← Transformer 链逐层变换 │ ├─→ custom MW1.onSystemPrompt() ├─→ custom MW2.onSystemPrompt() ├─→ WorkspaceContextMiddleware ← Session / Workspace / AGENTS / MEMORY / knowledge ├─→ TaskReminderMiddleware ← todo_write 使用说明 ├─→ PlanModeMiddleware ← Plan Mode 横幅 └─→ HarnessSkillMiddleware ← 技能列表 (available_skills) │ ▼ SystemMessage → 注入 reasoning 的消息列表首位关键设计seedSystemMsg()在每轮推理前被调用所以修改AGENTS.md或MEMORY.md立即生效Transformer链通过反射检测——只有真正重写了onSystemPrompt的中间件才参与变换避免不必要的block()调用3. 基础提示词3.1 设置方式HarnessAgent.builder().sysPrompt(你是一个有用的 AI 助手可以用中文回答问题。).build();3.2 存储位置sysPrompt存储在ReActAgent实例中// ReActAgent.javaprivatefinalStringsysPrompt;// BuilderpublicBuildersysPrompt(StringsysPrompt){this.sysPromptsysPrompt;returnthis;}4. Transformer 链实现4.1 源码入口在Agent每轮调用前都会通知所有钩子函数智能体即将启动其中会调用seedSystemMsg方法/** * 获取初始系统消息用于在钩子执行前填充至{link PreCallEvent}。 * * p默认实现返回{code null}。子类例如{code ReActAgent}会重写该方法 * 根据自身配置的{code sysPrompt}构建系统消息。 * * param callScope 调用入口捕获的单次调用作用域可为{code null} * 子类可通过该参数获取本次调用的{link RuntimeContext}用于系统提示词中间件 * 无需读取共享实例字段 * return 初始填充用系统消息无则返回{code null} */OverrideprotectedMsgseedSystemMsg(ObjectcallExectution){RuntimeContextrccallExectutioninstanceofCallExecutionce?ce.rc:getRuntimeContext();StringbasesysPrompt!null?sysPrompt.trim():;StringpromptapplySystemPromptMiddlewares(base,rc);if(promptnull||prompt.isEmpty()){returnnull;}returnSystemMessage.builder().name(system).content(TextBlock.builder().text(prompt).build()).build();}seedSystemMsg方法中会调用私有的applySystemPromptMiddlewares方法按顺序执行所有系统提示词中间件对原始系统提示词sysPrompt做拦截、修改、增强若无自定义中间件逻辑直接返回原提示词避免不必要的异步阻塞。// ReActAgent.java:536-569privateStringapplySystemPromptMiddlewares(Stringprompt,RuntimeContextctx){if(middlewares.isEmpty()){returnprompt;}// 通过反射检测哪些 middleware 真正重写了 onSystemPromptbooleanhasOverridefalse;for(MiddlewareBasemw:middlewares){if(mw.getClass().getMethod(onSystemPrompt,Agent.class,RuntimeContext.class,String.class).getDeclaringClass()!MiddlewareBase.class){hasOverridetrue;break;}}if(!hasOverride){returnprompt;// 短路没有任何 middleware 重写直接返回}// 从左到右串行接力MonoStringresultMono.just(prompt);for(MiddlewareBasemw:middlewares){resultresult.flatMap(p-mw.onSystemPrompt(this,ctx,p));}returnresult.block();}applySystemPromptMiddlewares方法的入参是【基础提示词】、【运行时上下文】4.2 反射检测通过反射检测哪些middleware真正重写了onSystemPrompt方法没有任何middleware重写直接返回// 注释翻译仅当至少一个中间件重写了onSystemPrompt方法时才构建响应式异步链路// 基类默认实现是直接入参原样返回该判断是为了避免无意义的block()阻塞调用// block()在非阻塞调度器如Reactor并行调度器中会抛出异常booleanhasOverridefalse;// 遍历全部中间件for(MiddlewareBasemw:middlewares){try{// 反射获取 onSystemPrompt(Agent, RuntimeContext, String) 方法// getDeclaringClass()获取该方法实际定义的类// 如果 ! MiddlewareBase说明子类重写了该方法存在自定义处理逻辑if(mw.getClass().getMethod(onSystemPrompt,Agent.class,RuntimeContext.class,String.class).getDeclaringClass()!MiddlewareBase.class){hasOverridetrue;break;}}catch(NoSuchMethodExceptionignored){// 极端异常找不到该方法视为存在自定义逻辑hasOverridetrue;break;}}关键设计MiddlewareBase是中间件基类自带默认onSystemPrompt逻辑为直接返回入参prompt无任何修改用反射判断中间件子类是否重写了该方法如果所有中间件都用基类默认实现 →hasOverridefalse直接返回原始prompt不走异步流程目的规避block()阻塞Reactor异步环境下随意调用block()会报错、破坏非阻塞性能。默认配置下自动装载了以下中间件4.3 串行执行当存在重写了onSystemPrompt方法的中间件时会构建异步处理链路串行执行中间件// 封装原始prompt为响应式Mono流MonoStringresultMono.just(prompt);// 循环串联所有中间件的onSystemPrompt串行执行// flatMap异步链式调用上一个中间件输出作为下一个输入for(MiddlewareBasemw:middlewares){resultresult.flatMap(p-mw.onSystemPrompt(this,ctx,p));}// 阻塞等待全部中间件异步处理完成拿到最终字符串返回returnresult.block();}Middleware列表按注册顺序排列onSystemPrompt从左到右串行接力原始 prompt → mw[0].onSystemPrompt → mw[1].onSystemPrompt → ... → 最终 prompt自定义 Middleware 跑在最前面因为HarnessAgent先注册用户Middleware再注册内置Middleware。4.4 系统提示词中间件所有中间件中有5个重写了onSystemPrompt方法WorkspaceContextMiddlewareDynamicSkillMiddlewareHarnessSkillMiddlewarePlanModeMiddlewareTaskReminderMiddleware在自动默认装载的8个只有2个按照执行顺序排列WorkspaceContextMiddlewareHarnessSkillMiddleware4.4.1 WorkspaceContextMiddleware核心作用自动向原始系统提示词尾部拼接工作区上下文片段工作空间路径、Agent配置、记忆、知识库、会话信息等同时做Token截断控长避免超出模型上下文窗口。重写onSystemPrompt钩子方法OverridepublicMonoStringonSystemPrompt(Agentagent,RuntimeContextctx,StringcurrentPrompt){// 兜底空上下文传入ctx为空则使用空白运行时上下文RuntimeContextrcctx!null?ctx:RuntimeContext.empty();// 组装工作区完整上下文段落StringsectionbuildWorkspaceSection(rc);// 无上下文内容直接返回原始提示词不做修改if(section.isEmpty()){returnMono.just(currentPrompt);}// 原始提示词兜底为空串StringbasecurrentPrompt!null?currentPrompt:;// 换行分隔符原始文本末尾已有换行则不加否则补换行排版整洁Stringseparatorbase.isEmpty()||base.endsWith(\n)?:\n;// 原始提示词 分隔换行 工作区上下文段落返回异步MonoreturnMono.just(baseseparatorsection);}核心上下文构建逻辑读取各类静态资源文件内容Token预算计算 记忆内容截断关键控长逻辑拼装所有模块生成完整附加段落privateStringbuildWorkspaceSection(RuntimeContextrc){// 读取工作区 agents.md、memory.md、knowledge.md 内容并去除首尾空白StringagentsContentworkspaceManager.readAgentsMd(rc).strip();StringmemoryContentworkspaceManager.readMemoryMd(rc).strip();StringknowledgeContentworkspaceManager.readKnowledgeMd(rc).strip();// 获取当前工作空间根路径PathworkspaceworkspaceManager.getWorkspace();// 构建会话专属上下文片段StringsessionContextbuildSessionContextSection(workspace,rc);// 封装知识库块文本StringknowledgeBlockbuildKnowledgeBlock(rc,knowledgeContent,workspace);// 扩展附加上下文自定义全局变量、权限、用户信息等StringadditionalBlockbuildAdditionalContextBlock(rc);// 计算固定占用Token会话信息、Agent配置、知识库、附加上下文intfixedTokensestimateTokens(sessionContext)estimateTokens(agentsContent)estimateTokens(knowledgeBlock)estimateTokens(additionalBlock);// 记忆文件单独Token消耗intmemoryTokensestimateTokens(memoryContent);// 剩余可用Token额度 最大上下文Token上限 - 固定内容占用量intavailablemaxContextTokens-fixedTokens;// 剩余额度充足但记忆文本超量 → 截断记忆内容至可用Token上限if(available0memoryTokensavailable){memoryContenttruncateToTokenBudget(memoryContent,available);// 工作空间描述段落路径、文件系统信息StringworkspaceParagraphbuildWorkspaceParagraph(workspace,workspaceManager.getFilesystem());// 整合四大块加载资源Agent配置、裁剪后记忆、知识库、附加上下文StringloadedContextbuildLoadedContextSection(agentsContent,memoryContent,knowledgeBlock,additionalBlock,rc);// 最终拼接会话上下文 固定引导模板 工作空间说明 所有加载资源returnassembleSection(sessionContext,GUIDANCE_TEMPLATE,workspaceParagraph,loadedContext);}组装结构## AgentStateStore Context This is the HarnessAgent. Todays date is 日期. My operating system is: OS The workspace directory is: 路径 The projects temporary directory is: 临时目录 ## Domain Knowledge / Memory Recall / Memory Persistence 引导段 内置模板教模型如何使用记忆系统和知识库 ## Workspace 按 filesystem 模式分支本机 / 沙箱 / 远端 ## Workspace Files (Injected) The following files were loaded from your workspace: loaded_context agents_context AGENTS.md 全文 /agents_context memory_context MEMORY.md超出 maxContextTokens 则截断 /memory_context domain_knowledge_context KNOWLEDGE.md 全文 knowledge/ 下所有文件路径清单 /domain_knowledge_context soul_mdadditionalContextFile 注入的额外文件/soul_md /loaded_context关键参数maxContextTokens默认8000控制MEMORY.md的注入预算。4.4.2 TaskReminderMiddleware仅在Builder未禁用Task功能时注册。onSystemPrompt注入todo_write工具的静态使用说明## Task List You have a todo_write tool that maintains a structured task list for this session. Use it for multi-step work: capture the plan as todos, keep exactly one task in_progress, and update the whole list as you make progress...onReasoning每轮推理前注入当前Todo列表的system-reminder块。4.4.3 PlanModeMiddlewarePLAN 模式注入只读设计阶段的提示横幅system-reminder PLAN MODE is active (read-only). Plan file: plans/PLAN.md Investigate the problem and draft a plan, but do NOT modify files... /system-reminderBUILD 模式刚从PLAN切出注入执行提示system-reminderYou have switched from PLAN to BUILD mode; the read-only restriction is lifted. An approved plan exists at plans/PLAN.md... /system-reminder4.4.4 HarnessSkillMiddleware注入当前可见技能列表渲染为available_skills块available_skills - code-reviewer: 代码评审专家 - pdf-extractor: Extract text from PDF documents /available_skills只列namedescriptionAgent判断相关后通过load_skill_through_path拉取完整指令。技能来源低优先级 → 高优先级重名覆盖projectGlobalSkillsDir(Path)— 项目全局skillRepository(...)— 市场后端Git/Nacos/MySQL/classpathworkspace/skills/— 工作区共用userId/skills/— 用户隔离4.4.5 SubagentsMiddleware通过 onReasoning不走onSystemPromptTransformer链而是通过onReasoning直接修改SYSTEM消息内容——将子Agent使用指南prepend到消息列表首条SYSTEM消息中## Subagents You have access to subagent tools for spawning and coordinating isolated subagents. ### Agent Tools - agent_spawn / agent_send / agent_list ### Available agent ids - reviewer: 代码评审专家 - researcher: 技术调研助手 ### When to use subagents / When NOT to use...4.5 最终 System Prompt 结构经过所有Transformer链处理后一次典型推理的最终SYSTEM消息结构如下[HarnessAgent.builder().sysPrompt(...)] ← 基础提示词 [自定义 Middleware 注入] ← 如果有 ## AgentStateStore Context ← WorkspaceContextMiddleware Todays date is ... My operating system is ... ## Domain Knowledge ← WorkspaceContextMiddleware ## Memory Recall ## Memory Persistence ## Workspace ← WorkspaceContextMiddleware Project: ... Workspace: ... ## Workspace Files (Injected) ← WorkspaceContextMiddleware loaded_context agents_contextAGENTS.md 全文/agents_context memory_contextMEMORY.md 全文受预算截断/memory_context domain_knowledge_contextKNOWLEDGE.md 路径清单/domain_knowledge_context /loaded_context ## Task List ← TaskReminderMiddleware todo_write 使用说明 system-reminderPLAN MODE is active.../system-reminder ← PlanModeMiddleware如开启 available_skills ← HarnessSkillMiddleware - skill-a: ... - skill-b: ... /available_skills5. 生命周期要点每轮推理前重新组装修改AGENTS.md、MEMORY.md、技能仓库后下一次call()立即生效不需要重启Agent。Transformer 链是同步阻塞的applySystemPromptMiddlewares()最后调用result.block()这意味着所有onSystemPrompt中的异步操作必须在返回前完成。实际内置Middleware的onSystemPrompt都是同步返回Mono.just()。自定义 Middleware 跑在最前面HarnessAgent先注册用户.middleware()的实例再注册内置Middleware。用户的onSystemPrompt可以看到最原始的sysPrompt。SubagentsMiddleware 的特殊性它不走onSystemPromptTransformer链而是通过onReasoning直接操作消息列表中的SYSTEM消息。这是因为子Agent信息需要在每轮推理前动态刷新文件系统可能随时新增子Agent声明而onSystemPrompt链只在seedSystemMsg时执行一次。