fix: delete agent 500 error + dynamic personality + deployment guide

- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions,
  schedules, executions, team_members) and unbind goals/tasks before delete
- Remove hardcoded personality templates in Android, replace with dynamic
  system prompt generation from name + description
- Set promptSectionsEnabled=false to bypass PromptComposer for personality
- Add Tencent Cloud Linux deployment guide (Docker Compose)
- Accumulated backend service updates, frontend UI fixes, Android app changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 01:17:21 +08:00
parent 86b98865e3
commit beff3fac8d
1084 changed files with 117315 additions and 1281 deletions

View File

@@ -21,6 +21,80 @@ _processed_msg_ids: deque[str] = deque(maxlen=20)
_ws_thread: threading.Thread | None = None
# ─── 错误友好提示映射 ───
_ERROR_FRIENDLY_MAP = {
"timeout": "处理超时,请稍后重试。若问题持续,可尝试简化问题描述。",
"connection": "网络连接异常,请稍后重试。",
"rate limit": "请求过于频繁,请稍候片刻再试。",
"invalid api key": "AI 模型密钥配置异常,请联系管理员检查 API Key。",
"insufficient_quota": "AI 模型额度已用完,请联系管理员处理。",
"context length": "对话内容过长,请简化你的问题后重试。",
"authentication": "飞书身份验证失败,请重新绑定飞书账号。",
}
def _friendly_error(error: Exception) -> str:
"""将技术异常映射为用户友好提示。"""
msg = str(error).lower()
for keyword, friendly in _ERROR_FRIENDLY_MAP.items():
if keyword in msg:
return f"{friendly}\n\n> 错误详情: {error!s}"
return f"处理请求时出现问题,请稍后重试。\n\n> 错误详情: {error!s}"
# ─── 对话历史上下文 ───
def _get_conversation_context(open_id: str, agent_id: str, max_messages: int = 5) -> str:
"""加载该用户在飞书上的近期对话历史,生成摘要上下文。
用于注入 Agent 系统提示词,使飞书对话保持连续性。
"""
try:
from app.core.database import SessionLocal
from app.models.user import User
from app.models.agent_execution_log import AgentExecutionLog
db = SessionLocal()
try:
user = db.query(User).filter(User.feishu_open_id == open_id).first()
if not user:
return ""
recent_logs = (
db.query(AgentExecutionLog)
.filter(
AgentExecutionLog.user_id == user.id,
AgentExecutionLog.agent_name.isnot(None),
)
.order_by(AgentExecutionLog.created_at.desc())
.limit(max_messages)
.all()
)
if not recent_logs:
return ""
# 按时间正序排列(最早的在前面)
recent_logs.reverse()
lines = ["\n## 近期对话历史(飞书)\n"]
for log in recent_logs:
if log.input_text:
lines.append(f"- **用户**: {log.input_text[:200]}")
if log.output_text:
summary = log.output_text[:200].replace("\n", " ")
lines.append(f" **回复概要**: {summary}")
lines.append("")
return "\n".join(lines)
finally:
db.close()
except Exception as e:
logger.warning("加载飞书对话历史失败: %s", e)
return ""
def _get_message_id(data) -> Optional[str]:
"""从 Feishu 消息事件中提取 message_id。"""
try:
@@ -150,12 +224,32 @@ def _reply_to_feishu(open_id: str, text: str):
logger.warning("飞书回复消息失败: %s", e)
def _reply_card(open_id: str, title: str, content: str, status: str = "info"):
"""通过飞书 API 回复卡片消息。"""
def _reply_error_card(open_id: str, title: str, content: str):
"""通过飞书 API 回复错误卡片消息。"""
try:
from app.services.feishu_app_service import send_message_to_user
send_message_to_user(open_id, title, content, status=status)
send_message_to_user(
open_id, title, content, status="failed",
execution_log_id=None, agent_name=None,
)
except Exception as e:
logger.warning("飞书错误卡片发送失败: %s", e)
# 降级为纯文本
_reply_to_feishu(open_id, content)
def _reply_card(open_id: str, title: str, content: str, status: str = "info",
execution_log_id: str = None, agent_name: str = None):
"""通过飞书 API 回复卡片消息(含反馈按钮)。"""
try:
from app.services.feishu_app_service import send_message_to_user
send_message_to_user(
open_id, title, content, status=status,
execution_log_id=execution_log_id,
agent_name=agent_name,
)
except Exception as e:
logger.warning("飞书回复卡片失败: %s", e)
@@ -243,7 +337,10 @@ async def _handle_message_async(data):
_reply_to_feishu(open_id, f"默认 Agent (id={agent_id}) 已不存在,请重新设置。")
return
_reply_to_feishu(open_id, f"🤔 正在思考,请稍候...")
_reply_to_feishu(open_id, f"🤔 正在分析你的问题并调用相关工具...\n\n对话将保持上下文连续性,你可随时追问。")
# 加载对话历史上下文,保持飞书对话连续性
conversation_context = _get_conversation_context(open_id, str(agent.id))
from app.agent_runtime import AgentRuntime, AgentConfig, AgentLLMConfig, AgentToolConfig, AgentMemoryConfig
@@ -268,10 +365,11 @@ async def _handle_message_async(data):
config = AgentConfig(
name=agent.name or "agent",
system_prompt=system_prompt + (
system_prompt=system_prompt + conversation_context + (
f"\n\n## 系统信息\n"
f"你的 Agent ID 是: {agent.id}\n"
f"在调用 schedule_list、schedule_delete 等工具时,使用此 ID 作为 agent_id 参数。"
f"在调用 schedule_list、schedule_delete 等工具时,使用此 ID 作为 agent_id 参数。\n"
f"你正在通过飞书与用户对话,回复应使用飞书支持的 Markdown 格式。"
),
llm=AgentLLMConfig(
model=model,
@@ -309,14 +407,44 @@ async def _handle_message_async(data):
on_llm_call = _make_llm_logger(db, agent_id=str(agent.id), user_id=user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
import time
_start_time = time.time()
result = await runtime.run(text)
_elapsed = time.time() - _start_time
if result.content:
# 查询刚写入的 AgentExecutionLog 获取 IDfire_and_forget 应已完成)
exec_log_id = None
try:
from app.models.agent_execution_log import AgentExecutionLog
exec_log = (
db.query(AgentExecutionLog)
.filter(AgentExecutionLog.agent_name == agent.name)
.order_by(AgentExecutionLog.created_at.desc())
.first()
)
if exec_log:
exec_log_id = str(exec_log.id)
except Exception:
pass
# 构建含处理状态信息的回复内容
status_footer = (
f"\n\n---\n"
f"🔄 迭代: {result.iterations_used} 次 | "
f"🔧 工具调用: {result.tool_calls_made} 次 | "
f"⏱ 耗时: {_elapsed:.1f}s"
)
reply_content = result.content.strip() + status_footer
_reply_card(
open_id,
f"🤖 {agent.name}",
result.content.strip(),
reply_content,
status="success",
execution_log_id=exec_log_id,
agent_name=agent.name,
)
else:
_reply_to_feishu(open_id, "Agent 未返回有效回复,请重试。")
@@ -329,7 +457,7 @@ async def _handle_message_async(data):
except Exception as e:
logger.error("飞书消息处理失败: %s", e)
try:
_reply_to_feishu(open_id, f"处理失败: {e!s}")
_reply_error_card(open_id, "处理失败", _friendly_error(e))
except Exception:
pass
finally:
@@ -338,7 +466,6 @@ async def _handle_message_async(data):
def _handle_message_internal(data):
"""同步入口 — 创建异步任务处理飞书消息(支持私信 + 群聊@提及)。"""
# 去重WS 重连后可能重投已处理的消息
msg_id = _get_message_id(data)
if msg_id:
@@ -394,7 +521,7 @@ def _handle_message_internal(data):
except Exception as e:
logger.error("创建飞书消息处理任务失败: %s", e)
try:
_reply_to_feishu(open_id, f"处理失败: {e!s}")
_reply_to_feishu(open_id, _friendly_error(e))
except Exception:
pass
@@ -486,7 +613,7 @@ async def _handle_group_mention_async(data, chat_id: str, open_id: str):
except Exception as e:
logger.error("群聊@提及处理失败: %s", e)
try:
_reply_to_group(chat_id, f"处理失败: {e!s}")
_reply_to_group(chat_id, _friendly_error(e))
except Exception:
pass
@@ -618,6 +745,13 @@ def _build_event_handler():
builder.register_p2_approval_instance_event_v1(on_approval_event)
# 卡片动作回调(用户点击反馈按钮)
def on_card_action(data):
from app.services.feishu_card_actions import handle_card_action
return handle_card_action(data)
builder.register_p2_card_action_trigger(on_card_action)
return builder.build()