Files
beaver_project/projcet_review/backend_blueprint/prompt-atlas.html
steven_li 6e9e74d1ee feat(engine): 添加运行时上下文支持并重构工具迭代限制
添加 RuntimeContext 类用于捕获模型运行时的日期时间信息,
包括UTC时间、本地时间和时区信息,并在系统提示中显示这些信息。

同时增加最大上下文消息数和工具迭代次数的配置选项,
将验证服务从引擎加载器中移除,并更新相关的数据结构和接口。

BREAKING CHANGE: 移除了验证服务,相关字段被替换为证据状态和接受状态。

- 添加 RuntimeContext 类和相关渲染方法
- 增加 max_context_messages 和 max_tool_iterations 配置
- 移除 ValidationService 相关代码
- 更新消息记录中的验证状态字段
- 添加原始工具调用检测和回退处理
2026-05-26 11:18:35 +08:00

218 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Prompt Atlas</title><link rel="stylesheet" href="blueprint.css"></head>
<body><main class="page">
<header class="topbar"><h1>Prompt Atlas</h1><p>这里集中记录后端所有直接组装 LLM messages 的位置。每段都按“谁调用、输入怎么来、system/user prompt 怎么拼、模型输出怎么解析、失败怎么 fallback”展开。</p></header>
<nav class="nav"><a href="index.html">索引</a><a href="services.html">Services</a><a href="engine.html">Engine</a><a href="tasks.html">Tasks</a><a href="skills.html">Skills</a><a href="coordinator.html">Coordinator</a></nav>
<section class="content">
<h2>总览流程</h2>
<div class="flow">
<div class="step"><strong>Intent Router</strong>是否 Task</div><div class="arrow">-&gt;</div>
<div class="step"><strong>Planner</strong>single/team</div><div class="arrow">-&gt;</div>
<div class="step"><strong>Skill 选择</strong>主 run / team node</div><div class="arrow">-&gt;</div>
<div class="step"><strong>Main Context</strong>身份/会话/记忆/技能/历史</div><div class="arrow">-&gt;</div>
<div class="step"><strong>Evidence</strong>事实记录</div><div class="arrow">-&gt;</div>
<div class="step"><strong>Learning</strong>accepted task evidence -> 草稿合成</div>
</div>
<h2 id="intent-router">1. MainAgentRouter</h2>
<p class="meta">文件:<code>beaver/tasks/router.py</code>;调用方:<code>AgentService._process_with_main_agent()</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>作用</td><td>只决定当前用户消息进入 simple chat 还是 internal Task mode不回答用户。</td></tr>
<tr><td>system message</td><td>声明自己是 Beaver 的 Intent Agent唯一职责是路由只返回紧凑 JSON不要回答用户不要解释。</td></tr>
<tr><td>user prompt 组成</td><td>固定说明“Decide how to route”可选 intent-agent-router skill guidanceActions 列表Critical policy返回 JSON keysActive task JSON最近 8 条 user/assistant 对话Current user message。</td></tr>
<tr><td>输出</td><td><code>{ action, reason, short_title }</code>。action 映射为 simple_chat、continue_task、revise_task、new_task、close_task、abandon_task。</td></tr>
<tr><td>fallback</td><td>provider 不可用或两次超时失败:有 active task 则 continue_task否则 simple_chat。</td></tr>
</table>
<div class="flow">
<div class="step">message + active_task + recent_messages</div><div class="arrow">-&gt;</div>
<div class="step">拼 router prompt</div><div class="arrow">-&gt;</div>
<div class="step">aux/main provider chat</div><div class="arrow">-&gt;</div>
<div class="step">parse JSON object</div><div class="arrow">-&gt;</div>
<div class="step">MainAgentDecision</div>
</div>
<pre>user prompt =
"Decide how to route..."
+ optional "Intent Agent skill guidance:\n{intent_skill}"
+ Actions 列表
+ Critical policy 列表
+ "Return JSON only with keys: action, reason, short_title."
+ "Active task:\n{json(active_task_payload)}"
+ "Recent conversation:\n{json(recent[-8:])}"
+ "Current user message:\n{message}"</pre>
<h2>2. TaskExecutionPlanner</h2>
<p class="meta">文件:<code>beaver/tasks/planner.py</code>;调用方:<code>AgentService._run_task_mode()</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>作用</td><td>决定本次 Task attempt 直接单 agent 执行,还是先创建 sub-agent team。</td></tr>
<tr><td>system message</td><td>选择 internal Beaver Task attempt 的执行模式;返回紧凑 JSON。</td></tr>
<tr><td>user prompt 组成</td><td>执行模式说明team 使用条件JSON schemaTask goalCurrent user requestAttempt index必要的 task history若有</td></tr>
<tr><td>输出</td><td><code>mode</code> 为 single 或 teamteam 时还需 <code>strategy</code><code>nodes</code><code>final_synthesis_instruction</code></td></tr>
<tr><td>fallback</td><td>provider 不可用、JSON 解析失败、graph validate 失败、skill resolver 失败都会回退 single。</td></tr>
</table>
<pre>planner user prompt =
"Decide execution mode for this internal Task attempt."
+ "Use mode=team only when ..."
+ JSON schema(mode/reason/strategy/nodes/final_synthesis_instruction)
+ "Task goal:\n{task.goal}"
+ "Current user request:\n{user_message}"
+ "Attempt index: {attempt_index}"
+ optional "Relevant task history:\n{task_history}"</pre>
<h2>3. TaskSkillResolver</h2>
<p class="meta">文件:<code>beaver/tasks/skill_resolver.py</code>调用方planner 解析 team graph 后</p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>query 组装</td><td><code>skill_query</code><code>node.task</code>、required capabilities、task.goal、user_message 用换行拼接。</td></tr>
<tr><td>召回</td><td>SkillsLoader 构建候选EmbeddingRetriever top-8。</td></tr>
<tr><td>system message</td><td>为一个 generic sub-agent node 选择 published Beaver skills只返回 JSON array不能编造名字不匹配返回 []。</td></tr>
<tr><td>user prompt</td><td>Node skill queryCandidate skills 列表;要求返回 JSON例如 <code>["skill-a"]</code><code>[]</code></td></tr>
<tr><td>输出过滤</td><td>只保留候选集中真实存在的 skill name并保持模型输出顺序。</td></tr>
<tr><td>fallback</td><td>LLM 失败或返回空时,进入 EphemeralGuidanceSynthesizer。</td></tr>
</table>
<pre>node skill query =
join_non_empty(skill_query, node.task, " ".join(required_capabilities), task.goal, user_message)</pre>
<h2>4. EphemeralGuidanceSynthesizer</h2>
<p class="meta">文件:<code>beaver/skills/learning/missing_skill.py</code>调用方TaskSkillResolver</p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>作用</td><td>team node 没有 published skill 可用时,生成当前委派子任务专用的一次性 guidance。</td></tr>
<tr><td>system message</td><td>创建 concise Beaver ephemeral guidance只返回 JSON keysguidance_name、description、content、tags。</td></tr>
<tr><td>user prompt</td><td>说明“Create procedural guidance”Task goalCurrent user requestNode idNode taskSkill queryRequired capabilities要求 content 是临时 sub-agent 可执行指导不包含实现声明、review metadata 或 publish metadata。</td></tr>
<tr><td>输出</td><td>生成 <code>SkillContext(name="ephemeral:{guidance_name}", version="ephemeral:{guidance_id}")</code></td></tr>
<tr><td>fallback</td><td>失败时本地生成基础 payloadObjective、Capabilities to apply、Output。</td></tr>
</table>
<h2 id="skill-assembler">5. SkillAssembler</h2>
<p class="meta">文件:<code>beaver/skills/assembler/task_assembler.py</code>;调用方:<code>AgentLoop._process_direct_impl()</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>query 来源</td><td>默认是 taskTask 模式会传入 AgentService 组装的 skill_selection_contextteam node 会传 LocalAgentRunner 组装的 delegated skill_selection_context。</td></tr>
<tr><td>召回</td><td>SkillsLoader candidates -> EmbeddingRetriever top-k。</td></tr>
<tr><td>shortlist</td><td>候选数超过 max_detailed_candidates 时LLM 先基于摘要返回最多 N 个 skill names。</td></tr>
<tr><td>final</td><td>把 shortlist 对应候选补充 skill 正文,再让 LLM 返回最终要激活的 skill names。</td></tr>
<tr><td>system message</td><td>选择 Beaver skills输入 task description 和 candidate skill information只返回 JSON array不能编造名字无匹配返回 [];包含 selection stage 和返回数量指令。</td></tr>
<tr><td>user prompt</td><td>Task descriptionCandidate skills返回 JSON 示例。</td></tr>
<tr><td>注入</td><td>加载 skill 正文并 strip frontmatter生成 SkillContext稍后由 ContextBuilder 转成 activation message。</td></tr>
</table>
<pre>skill selector messages =
system: "You select Beaver skills for a single run..." + "Selection stage: {shortlist|final}..."
user: "Task description:\n{task_description}\n\nCandidate skills:\n{candidate_summary}\n\nReturn only JSON..."</pre>
<h2 id="agent-service-contexts">6. AgentService 组装的上下文片段</h2>
<p class="meta">文件:<code>beaver/services/agent_service.py</code></p>
<article class="module">
<h3>Task skill selection context</h3>
<p>传给 SkillAssembler 的 task_description。它不是 provider chat 的最终 prompt但会影响选中哪些 skills。</p>
<div class="subflow">
<div>Task goal / description / current user request。</div>
<div>Execution phase、task status、attempt index。</div>
<div>constraints、prior skills、必要的 task history。</div>
<div>planner reason、strategy、nodes、team summaries、final synthesis instruction。</div>
<div>明确要求优先选择 existing published skills。</div>
</div>
</article>
<article class="module">
<h3>Team execution context</h3>
<p>如果 team 先跑,主 agent 的 execution_context 会包含 planner reason、team strategy、team success、node results、rendered team evidence、final synthesis instruction以及避免重复失败工具调用的提醒。</p>
</article>
<article class="module">
<h3>Scheduled execution context</h3>
<p>cron task/notification 会把 Cron Job ID、Name、Scheduled Run ID 和“不向用户确认,直接执行/生成通知”的约束放进 execution_context。</p>
</article>
<h2 id="delegated-contexts">7. LocalAgentRunner delegated contexts</h2>
<p class="meta">文件:<code>beaver/coordinator/local.py</code></p>
<table class="table">
<tr><th>上下文</th><th>拼装内容</th></tr>
<tr><td>execution_context</td><td>Parent task ID、Parent run ID、delegated worker 说明、agent.system_prompt、constraints、expected output、dependency outputs、pinned inherited skills、ephemeral pinned guidance。</td></tr>
<tr><td>skill_selection_context</td><td>Parent task ID、Node task、Execution phase=team_node、Agent role、Skill query、Required capabilities、constraints、expected output、pinned skills、dependency outputs 前 800 字、Skill selection instruction。</td></tr>
</table>
<div class="flow">
<div class="step">DelegationEnvelope</div><div class="arrow">-&gt;</div>
<div class="step">child session id</div><div class="arrow">-&gt;</div>
<div class="step">execution_context</div><div class="arrow">+</div>
<div class="step">skill_selection_context</div><div class="arrow">-&gt;</div>
<div class="step">AgentLoop.process_direct</div>
</div>
<h2 id="agent-loop">8. AgentLoop 主运行 prompt</h2>
<p class="meta">文件:<code>beaver/engine/loop.py</code><code>beaver/engine/context/builder.py</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>base identity</td><td>固定 Beaver 身份海狸Beaver博维资讯系统有限公司研发的 AI 助手。</td></tr>
<tr><td>base system prompt</td><td>AgentProfile.system_prompt。</td></tr>
<tr><td>session section</td><td>Session ID、Source、Model、User ID、Channel、Chat ID、Parent Session ID。</td></tr>
<tr><td>execution context</td><td>Service 或 LocalAgentRunner 传入,标题为 <code># Execution Context</code></td></tr>
<tr><td>memory snapshot</td><td>MemorySnapshot.as_prompt_sections() 的 frozen sections。</td></tr>
<tr><td>extra sections</td><td>当前固定加入 Tool Failure Guidance。</td></tr>
<tr><td>skill activation</td><td>每个 SkillContext 变成一条 user message位于 system prompt 之后、历史消息之前。</td></tr>
<tr><td>history</td><td>session_manager.get_history()ContextBuilder 跳过 role=system 的历史。</td></tr>
<tr><td>current user</td><td>本轮 task/message 作为最后一条 user message。</td></tr>
</table>
<pre>messages =
[
{"role": "system", "content": build_system_prompt(...)},
...build_skill_activation_messages(activated_skills),
...visible_history_without_system,
{"role": "user", "content": current_user_input}
]</pre>
<h3>Tool Failure Guidance</h3>
<p>AgentLoop 把一段额外 section 放进 system prompt如果同类工具反复失败不要继续换 query 重试;使用已有材料,明确不确定性,给出部分已确认结果。</p>
<h3>Tool iteration finalizer</h3>
<p>到达最大工具迭代数后AgentLoop 追加一条新的 system message要求工具预算已耗尽、不要再调用工具、基于现有对话和工具结果给出最终答案并明确不确定性。该 finalizer 只用于最后一次无工具收尾调用。</p>
<h2>9. Tool loop 消息追加</h2>
<p class="meta">文件:<code>beaver/engine/context/builder.py</code><code>beaver/engine/loop.py</code></p>
<div class="flow">
<div class="step">provider response</div><div class="arrow">-&gt;</div>
<div class="step">assistant message(content + tool_calls)</div><div class="arrow">-&gt;</div>
<div class="step">ToolExecutor</div><div class="arrow">-&gt;</div>
<div class="step">tool message(tool_call_id/name/content)</div><div class="arrow">-&gt;</div>
<div class="step">下一轮 provider chat</div>
</div>
<p>assistant 消息始终显式包含 <code>content</code>即使工具调用时为空tool_calls 会被规范化为 OpenAI-compatible 结构arguments 非字符串时转 JSON 字符串。</p>
<h2>10. Task Evidence</h2>
<p class="meta">文件:<code>beaver/tasks/evidence.py</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>作用</td><td>记录 Task run 的事实证据,不判断、不打分、不 gate也不生成 revision prompt。</td></tr>
<tr><td>输入</td><td>Task goal、attempt index、main run、team runs、tool results、team node results、assistant final output。</td></tr>
<tr><td>输出</td><td>TaskEvidencePacket / rendered evidence text供审计、过程展示和 skill learning 使用。</td></tr>
<tr><td>边界</td><td>Task 是否完成只由 User Acceptance 决定accepted task evidence 包含 task 的所有 runs并标记 final_accepted_run_id。</td></tr>
</table>
<h2>11. SkillDraftSynthesizer</h2>
<p class="meta">文件:<code>beaver/skills/learning/synthesizer.py</code></p>
<table class="table">
<tr><th>阶段</th><th>内容</th></tr>
<tr><td>作用</td><td>从 accepted task evidence 合成 skill 草稿,支持 new/revise/merge。</td></tr>
<tr><td>system message</td><td>从 accepted task evidence 合成 Beaver skill drafts只返回 JSON keysfrontmatter、content、change_reason。</td></tr>
<tr><td>user prompt</td><td>ActionCandidate kindReasonRelated skillsCalled tool namesRun-selected tool namesTask summariesSession excerptsfinal_accepted_run_idfrontmatter 必须包含 description 和 tools 数组。</td></tr>
<tr><td>输出 normalize</td><td>frontmatter.tools 为空时用 evidence_packet.metadata.tool_names 补齐。</td></tr>
<tr><td>fallback</td><td>JSON 不合格时本地生成基础 frontmatter 和 Evidence 内容。</td></tr>
</table>
<h2 id="provider-conversion">12. Provider conversion</h2>
<p class="meta">文件:<code>beaver/engine/providers/*</code></p>
<p>Provider 层不负责创造业务 prompt但会改变 messages 的传输形式。Anthropic/Codex 类 provider 会把第一条 system message 拆出来传给 SDK 的 <code>system</code><code>instructions</code> 字段,剩余 messages 作为对话OpenAI/LiteLLM 风格 provider 基本保留 messages + tools。</p>
<div class="subflow">
<div>ContextBuilder 输出统一 messages。</div>
<div>Provider adapter 根据目标 SDK 转换 system、tools、tool calls、usage、reasoning。</div>
<div>响应统一回 LLMResponseAgentLoop 不感知 SDK 差异。</div>
</div>
<h2>13. 无 LLM prompt 但影响 prompt 的组件</h2>
<table class="table">
<tr><th>组件</th><th>影响</th></tr>
<tr><td>ToolAssembler</td><td>不调用 LLM但决定哪些 tool schema 暴露给主模型。</td></tr>
<tr><td>MemoryService</td><td>不调用 LLM但 frozen snapshot 会进入 system prompt。</td></tr>
<tr><td>SessionManager</td><td>不调用 LLM但可见历史决定 ContextBuilder 的 history。</td></tr>
<tr><td>SkillDraftSafetyChecker</td><td>不调用 LLM是 deterministic safety gate影响草稿是否能进入后续审核。</td></tr>
</table>
</section></main></body></html>