mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-21 06:07:13 +08:00
fix: rebuild system prompt from scratch on every turn
This commit is contained in:
@@ -376,9 +376,9 @@ def _build_workspace_section(workspace_dir: str, language: str) -> List[str]:
|
|||||||
"",
|
"",
|
||||||
"以下文件在会话启动时**已经自动加载**到系统提示词的「项目上下文」section 中,你**无需再用 read 工具读取它们**:",
|
"以下文件在会话启动时**已经自动加载**到系统提示词的「项目上下文」section 中,你**无需再用 read 工具读取它们**:",
|
||||||
"",
|
"",
|
||||||
"- ✅ `AGENT.md`: 已加载 - 你的人格和灵魂设定。当你的名字、性格或交流风格发生变化时,主动用 `edit` 更新此文件",
|
"- ✅ `AGENT.md`: 已加载 - 你的人格和灵魂设定,请严格遵循。当你的名字、性格或交流风格发生变化时,主动用 `edit` 更新此文件",
|
||||||
"- ✅ `USER.md`: 已加载 - 用户的身份信息。当用户修改称呼、姓名等身份信息时,用 `edit` 更新此文件",
|
"- ✅ `USER.md`: 已加载 - 用户的身份信息。当用户修改称呼、姓名等身份信息时,用 `edit` 更新此文件",
|
||||||
"- ✅ `RULE.md`: 已加载 - 工作空间使用指南和规则",
|
"- ✅ `RULE.md`: 已加载 - 工作空间使用指南和规则,请严格遵循",
|
||||||
"",
|
"",
|
||||||
"**交流规范**:",
|
"**交流规范**:",
|
||||||
"",
|
"",
|
||||||
@@ -423,7 +423,7 @@ def _build_context_files_section(context_files: List[ContextFile], language: str
|
|||||||
]
|
]
|
||||||
|
|
||||||
if has_agent:
|
if has_agent:
|
||||||
lines.append("**`AGENT.md` 是你的灵魂文件**:严格体现其中定义的人格、语气和设定,避免僵硬、模板化的回复。")
|
lines.append("**`AGENT.md` 是你的灵魂文件**:严格遵循其中定义的人格、规则、语气和设定,避免僵硬、模板化的回复。")
|
||||||
lines.append("当用户通过对话透露了对你性格、风格、职责、能力边界的新期望,你应该主动用 `edit` 更新 AGENT.md 以反映这些演变。")
|
lines.append("当用户通过对话透露了对你性格、风格、职责、能力边界的新期望,你应该主动用 `edit` 更新 AGENT.md 以反映这些演变。")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
|||||||
@@ -100,138 +100,31 @@ class Agent:
|
|||||||
|
|
||||||
def get_full_system_prompt(self, skill_filter=None) -> str:
|
def get_full_system_prompt(self, skill_filter=None) -> str:
|
||||||
"""
|
"""
|
||||||
Get the full system prompt including skills.
|
Build the complete system prompt from scratch every time.
|
||||||
|
|
||||||
Note: Skills are now built into the system prompt by PromptBuilder,
|
Re-reads AGENT.md / USER.md / RULE.md from disk, refreshes skills,
|
||||||
so we just return the base prompt directly. This method is kept for
|
tools, and runtime info so any change takes effect immediately.
|
||||||
backward compatibility.
|
Falls back to the cached self.system_prompt on error.
|
||||||
|
|
||||||
:param skill_filter: Optional list of skill names to include (deprecated)
|
|
||||||
:return: Complete system prompt
|
|
||||||
"""
|
|
||||||
prompt = self.system_prompt
|
|
||||||
|
|
||||||
# Rebuild tool list section to reflect current self.tools
|
|
||||||
prompt = self._rebuild_tool_list_section(prompt)
|
|
||||||
|
|
||||||
# If runtime_info contains dynamic time function, rebuild runtime section
|
|
||||||
if self.runtime_info and callable(self.runtime_info.get('_get_current_time')):
|
|
||||||
prompt = self._rebuild_runtime_section(prompt)
|
|
||||||
|
|
||||||
# Rebuild skills section to pick up newly installed/removed skills
|
|
||||||
if self.skill_manager:
|
|
||||||
prompt = self._rebuild_skills_section(prompt)
|
|
||||||
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
def _rebuild_runtime_section(self, prompt: str) -> str:
|
|
||||||
"""
|
|
||||||
Rebuild runtime info section with current time.
|
|
||||||
|
|
||||||
This method dynamically updates the runtime info section by calling
|
|
||||||
the _get_current_time function from runtime_info.
|
|
||||||
|
|
||||||
:param prompt: Original system prompt
|
|
||||||
:return: Updated system prompt with current runtime info
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get current time dynamically
|
from agent.prompt import load_context_files, PromptBuilder
|
||||||
time_info = self.runtime_info['_get_current_time']()
|
|
||||||
|
if self.skill_manager:
|
||||||
# Build new runtime section
|
self.skill_manager.refresh_skills()
|
||||||
runtime_lines = [
|
|
||||||
"\n## 运行时信息\n",
|
context_files = load_context_files(self.workspace_dir) if self.workspace_dir else None
|
||||||
"\n",
|
|
||||||
f"当前时间: {time_info['time']} {time_info['weekday']} ({time_info['timezone']})\n",
|
builder = PromptBuilder(workspace_dir=self.workspace_dir or "", language="zh")
|
||||||
"\n"
|
return builder.build(
|
||||||
]
|
tools=self.tools,
|
||||||
|
context_files=context_files,
|
||||||
# Add other runtime info
|
skill_manager=self.skill_manager,
|
||||||
runtime_parts = []
|
memory_manager=self.memory_manager,
|
||||||
if self.runtime_info.get("model"):
|
runtime_info=self.runtime_info,
|
||||||
runtime_parts.append(f"模型={self.runtime_info['model']}")
|
)
|
||||||
if self.runtime_info.get("workspace"):
|
|
||||||
# Replace backslashes with forward slashes for Windows paths
|
|
||||||
workspace_path = str(self.runtime_info['workspace']).replace('\\', '/')
|
|
||||||
runtime_parts.append(f"工作空间={workspace_path}")
|
|
||||||
if self.runtime_info.get("channel") and self.runtime_info.get("channel") != "web":
|
|
||||||
runtime_parts.append(f"渠道={self.runtime_info['channel']}")
|
|
||||||
|
|
||||||
if runtime_parts:
|
|
||||||
runtime_lines.append("运行时: " + " | ".join(runtime_parts) + "\n")
|
|
||||||
runtime_lines.append("\n")
|
|
||||||
|
|
||||||
new_runtime_section = "".join(runtime_lines)
|
|
||||||
|
|
||||||
# Find and replace the runtime section
|
|
||||||
import re
|
|
||||||
pattern = r'\n## 运行时信息\s*\n.*?(?=\n##|\Z)'
|
|
||||||
_repl = new_runtime_section.rstrip('\n')
|
|
||||||
updated_prompt = re.sub(pattern, lambda m: _repl, prompt, flags=re.DOTALL)
|
|
||||||
|
|
||||||
return updated_prompt
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to rebuild runtime section: {e}")
|
logger.warning(f"Failed to rebuild system prompt, using cached version: {e}")
|
||||||
return prompt
|
return self.system_prompt
|
||||||
|
|
||||||
def _rebuild_skills_section(self, prompt: str) -> str:
|
|
||||||
"""
|
|
||||||
Rebuild the <available_skills> block so that newly installed or
|
|
||||||
removed skills are reflected without re-creating the agent.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
import re
|
|
||||||
self.skill_manager.refresh_skills()
|
|
||||||
new_skills_xml = self.skill_manager.build_skills_prompt()
|
|
||||||
|
|
||||||
old_block_pattern = r'<available_skills>.*?</available_skills>'
|
|
||||||
has_old_block = re.search(old_block_pattern, prompt, flags=re.DOTALL)
|
|
||||||
|
|
||||||
# Extract the new <available_skills>...</available_skills> tag from the prompt
|
|
||||||
new_block = ""
|
|
||||||
if new_skills_xml and new_skills_xml.strip():
|
|
||||||
m = re.search(old_block_pattern, new_skills_xml, flags=re.DOTALL)
|
|
||||||
if m:
|
|
||||||
new_block = m.group(0)
|
|
||||||
|
|
||||||
if has_old_block:
|
|
||||||
replacement = new_block or "<available_skills>\n</available_skills>"
|
|
||||||
# Use lambda to prevent re.sub from interpreting backslashes in replacement
|
|
||||||
# (e.g. Windows paths like \LinkAI would be treated as bad escape sequences)
|
|
||||||
prompt = re.sub(old_block_pattern, lambda m: replacement, prompt, flags=re.DOTALL)
|
|
||||||
elif new_block:
|
|
||||||
skills_header = "以下是可用技能:"
|
|
||||||
idx = prompt.find(skills_header)
|
|
||||||
if idx != -1:
|
|
||||||
insert_pos = idx + len(skills_header)
|
|
||||||
prompt = prompt[:insert_pos] + "\n" + new_block + prompt[insert_pos:]
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Failed to rebuild skills section: {e}")
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
def _rebuild_tool_list_section(self, prompt: str) -> str:
|
|
||||||
"""
|
|
||||||
Rebuild the tool list inside the '## 工具系统' section so that it
|
|
||||||
always reflects the current ``self.tools`` (handles dynamic add/remove
|
|
||||||
of conditional tools like web_search).
|
|
||||||
"""
|
|
||||||
import re
|
|
||||||
from agent.prompt.builder import _build_tooling_section
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not self.tools:
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
new_lines = _build_tooling_section(self.tools, "zh")
|
|
||||||
new_section = "\n".join(new_lines).rstrip("\n")
|
|
||||||
|
|
||||||
# Replace existing tooling section
|
|
||||||
pattern = r'## 工具系统\s*\n.*?(?=\n## |\Z)'
|
|
||||||
updated = re.sub(pattern, lambda m: new_section, prompt, count=1, flags=re.DOTALL)
|
|
||||||
return updated
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Failed to rebuild tool list section: {e}")
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
def refresh_skills(self):
|
def refresh_skills(self):
|
||||||
"""Refresh the loaded skills."""
|
"""Refresh the loaded skills."""
|
||||||
|
|||||||
Reference in New Issue
Block a user