PowerCore 集成(PE Agent 实现说明)¶
当前章节还未完善
本文面向 PE Agent 本仓库开发者,说明 app/integrations/ai_power/ 如何在项目内落地 AI Power 平台协议:鉴权、HTTP、WebSocket、SSE 转发、业务 flow 与排错约定。
简化版说明:当前仓库已裁剪为
auth/user/agent核心能力;智能体在 AI Power 平台侧预置,本地Agent表仅维护展示元数据。下文配置表与 flow 列表以当前代码为准。
若要把协议交给外部系统自行对接 AI Power,请参阅 PE Agent 集成(平台对接指南)。开放 API 见 接口 API。
1. 集成边界¶
AI Power 是 PE Agent 依赖的外部智能体运行时。项目内约定:
- 业务模块优先从
app.integrations.ai_power导入核心能力(鉴权、流式、任务 HTTP);扩展 HTTP(read_directory、LLM Keys、LightRAG)可直接引用http/子模块。 - 协议字段以 AI Power 平台为准,PE Agent 的实现说明只描述本仓库当前封装方式。
- 新任务必须先建 WebSocket,再调用
enter_agent,否则平台在enter_agent后立即推送的帧可能丢失。 - WebSocket 按用户持有物理连接,按 link 隔离并发请求;最后一条 link 结束后立即关闭物理连接,不做跨请求常连。
业务模块 (auth / user / agent / tasks / scheduler)
│
▼
app/integrations/ai_power/ ← 对外唯一入口 (__init__.py)
├── auth/ App token、user token、add_user / user_login
├── http/ REST 客户端、文件上传下载/目录读取、用户 LLM Keys、LightRAG
├── agents/ enter / refresh / modify / pause(tasks.py)
├── streaming/ 上游 WS 帧 → 前端 SSE 事件
├── ws/ AiPowerChatWS,单连接多 link 路由
├── ws_pool/ 按 user.id 管理活跃 WS 会话
├── parser/ executing / 交付物解析
└── task_ids.py task_id 规范化比较
│
▼
AI Power 平台 (HTTP + WebSocket)
2. 配置¶
配置由 app/core/config.py 聚合成 settings.ai_power_paths。AI Power 根地址和应用凭据由 .env 提供,固定 Path 默认写在 config.py;如确需临时覆盖,仍可使用同名环境变量。
2.1 连接与路径¶
| 配置项 | 当前默认 | 用途 |
|---|---|---|
AI_POWER_API_URL |
环境配置 | AI Power HTTP 根地址 |
AI_POWER_APP_ID / AI_POWER_APP_SKEY |
环境配置 | 应用级签名凭据 |
AI_POWER_GET_ACCESS_TOKEN_PATH |
/peagent/api/get_token |
获取 App access_token |
AI_POWER_GENERATE_ADD_USER_PATH |
/peagent/api/add_user |
注册 AI Power 用户 |
AI_POWER_GENERATE_USER_LOGIN_PATH |
/peagent/api/user_login |
获取用户 user_token |
AI_POWER_ENTER_AGENT_PATH |
/peagent/api/enter_agent |
创建任务 |
AI_POWER_SOCKET_PATH |
/peagent/api/chat_ws |
WebSocket 路径 |
AI_POWER_AGENT_RE_GENERATE_PATH |
/peagent/api/re_generate |
重新生成 |
AI_POWER_AGENT_MODIFY_LLM_RESPONSE_PATH |
/peagent/api/modify_llm_response |
编辑 LLM 回复后继续收流 |
AI_POWER_PAUSE_TASK_PATH |
/peagent/api/pause_task |
暂停任务 |
AI_POWER_UPLOAD_FILE_PATH |
/peagent/api/common/upload_file |
上传文件 |
AI_POWER_DOWNLOAD_FILE_PATH |
/peagent/api/common/download_file |
下载文件 |
AI_POWER_REPLACE_MY_FILE_PATH |
/peagent/api/replace_my_file |
替换个人文件内容(支持子目录) |
AI_POWER_READ_DIRECTORY_PATH |
/peagent/common/read-directory |
读取目录内容(App token,见 §9) |
AI_POWER_USER_LLM_KEYS_PATH |
/peagent/user-llm-keys |
用户大模型密钥(见 §9.2) |
AI_POWER_LIGHTRAG_OPEN_GRAPHS_PATH |
/lightrag/open_graphs |
知识图谱(见 §9.3) |
本地 Agent 表维护展示用元数据;运行时使用库中 agent_id 调用 enter_agent,不在 PE Agent 内创建/更新 AI Power 侧 Agent。
2.2 特殊业务 Agent(本地 category)¶
不再配置 AI Power Agent ID。将本地 agent.category 设为:
category |
含义 |
|---|---|
current |
即时任务清单 |
scheduled |
定时任务清单 |
experts |
专家团队(总入口;异常续跑接入点、隐藏消息落库) |
task_note 由 task_note_type_for_agent_category 识别;专家团队 / 总入口逻辑由 is_experts_agent_category 识别。所有 Agent 的「结束」节点正文均不向前端透传(见 should_skip_agent_content)。
已移除的配置项(勿再添加):AI_POWER_HUMAN_MACHINE_DELIVERY_AGENT_ID、AI_POWER_CURRENT_TASK_AGENT_ID、AI_POWER_SCHEDULED_TASK_AGENT_ID、hide_end_ids / AI_POWER_HIDE_END_AGENT_IDS、settings.ai_power_agents 等历史 Agent ID 配置。
3. 鉴权¶
AI Power 使用两级 token:
| Token | 获取方式 | 使用位置 |
|---|---|---|
access_token |
app_id + timestamp + app_skey 计算 HMAC-SHA256 签名,调用 get_token |
add_user、user_login 等系统级接口 |
user_token |
用 PE Agent 用户 external_user_id=str(user.id) 调用 user_login |
enter_agent、文件接口、LLM Keys、WS query token |
3.1 App Token¶
实现位置:auth/app_token.py、auth/token_manager.py。
签名规则与平台指南一致:
raw = app_id + timestamp + app_skey
signature = HMAC_SHA256(key=app_skey, message=raw).hexdigest().lower()
请求头:
TokenManager 使用 Redis 缓存,key 为 ai_power:access_token。缓存写入时会把业务过期时间提前 100~300 秒,并额外保留约 1 小时陈旧缓存;刷新失败且仍有缓存时,会降级使用旧 token。
3.2 用户 Token 与用户注册¶
实现位置:auth/user.py、modules/auth/service.py。
注册 AI Power 用户:
{
"external_user_id": "PE Agent user.id",
"nickname": "user.name 或 PE_AGENT{id}",
"tel": "user.phone"
}
注册返回的 user_id 会写入 User.ai_power_user_id。用户登录请求:
TokenManager.get_user_token(user) 按 user.id 缓存 Redis key:ai_power:user_token:{user.id},并按用户粒度加锁,避免并发刷新同一用户 token。
3.3 请求头约定¶
系统级接口:
用户级接口:
WebSocket 建连 URL 由 ws/protocol.py 生成:
4. HTTP 客户端规范¶
统一入口:http/client.py。
核心行为:
- 使用线程本地
requests.Session复用 HTTP 连接。 - 所有 JSON 接口只认响应体
code == 200为成功(get_direct()除外,见下)。 - 非 JSON、HTTP 4xx/5xx、业务
code != 200都会记录日志,并转换为统一前端文案USER_FACING_ERROR = "服务暂时不可用,请稍后重试"。 - 文件上传使用
post_file(),会移除Content-Type,让requests自动生成multipart/form-databoundary。 - 文件下载使用
get_raw(),直接返回二进制bytes。 get_lenient():GET 请求,失败时不抛异常、返回None;用于read_directory等可选资源加载。get_direct():GET 请求,上游直接返回 JSON 体(无code/data包装);根地址与其它接口相同,走AI_POWER_API_URL。
业务层不应直接拼 URL 或直接调用 requests,应使用 app.integrations.ai_power 导出的函数。
5. 任务级 HTTP 能力¶
实现位置:agents/tasks.py。
5.1 enter_agent¶
请求体:
注意:当前实现会把 agent_id 转为字符串提交。返回体必须包含 data.task_id,否则抛业务异常。
5.2 task_refresh¶
用于重新生成:
请求体:
{
"task_id": 987654321,
"content": "用户补充说明",
"message_id": "msg_xxx",
"agent_id": 2157,
"node_id": 100
}
平台会返回新的 task_id。调用方必须立刻执行:
否则后续 WS 帧会因为无路由被丢弃。
5.3 modify_llm_response¶
用于编辑已有 LLM 回复:
请求体:
SSE 编辑入口使用 modify_llm_response_stream():先建立 WS session 并绑定原 task_id,再调用 HTTP 修改接口,随后继续从 WS 接收 stream / refine。收到 refine 后,modules/agent/service/user_agent/modify.py 会更新本地消息与报告来源内容,并下发 message_full。
5.4 pause_task¶
请求体:
入口在 modules/agent/service/user_agent/run_stream/context.py(SSE 异常或客户端断开时调用,用于终止当前执行)。
6. WebSocket 架构¶
6.1 核心类¶
AiPowerChatWS 位于 ws/chat_ws.py,由多个 mixin 组合:
| Mixin | 文件 | 职责 |
|---|---|---|
ConnectionMixin |
ws/connection.py |
建连、断连、重连 |
ReceiverMixin |
ws/receiver.py |
后台接收线程 |
TransportMixin |
ws/transport.py |
send 与 _safe_recv |
IncomingRouterMixin |
ws/incoming_router.py |
入站帧校验、task_id 路由、任务切换 |
LinkOpsMixin |
ws/link_ops.py |
link 队列、task_id -> link_id 映射 |
LinkErrorsMixin |
ws/link_errors.py |
链路级错误传播 |
CommandsMixin |
ws/commands.py |
dialog / confirm / recv_stream |
不要在接收线程外直接 ws.recv();业务只消费 recv_stream()、dialog()、confirm() 这些按 link 隔离后的迭代器。
6.2 物理 WS 与 link¶
AiPowerWSPool 位于 ws_pool/pool.py。它按 user.id 维护一条当前活跃物理 WS,但这不是跨请求常连池:
with get_ai_power_ws_pool().session(user) as sess:
→ entry.ws 不存在时 connect()
→ begin_link(link_id)
→ yield sess
→ end_link(link_id)
→ 如果 open_link_count() == 0,立即关闭 socket,entry.ws = None
只有同一用户的多个 session() 在时间上重叠时,才会复用同一条物理连接并挂多个 link:
user.id
└─ AiPowerChatWS(活跃物理连接)
├─ link-A → Queue(maxsize=2000)
├─ link-B → Queue(maxsize=2000)
└─ link-C → Queue(maxsize=2000)
link_id 默认取当前 trace_id,没有 trace 时使用 uuid4().hex。SSE 入口会通过 link_id_holder 把当前 link 回写给断连收尾逻辑。
6.3 新任务标准顺序¶
SSE 主链路在 streaming/raw.py 的 run_agent_stream_raw() 中实现,标准顺序为:
1. pool.session(user) → WS connect + begin_link
2. enter_agent(user, agent_id, message) → task_id
3. ws.associate_task_with_link(task_id, link_id)
4. yield task_start,再消费 recv_stream(link_id=link_id)
5. session 退出 → end_link;最后一个 link 结束时关闭物理 WS
ws/session.py 仅保留 fill_link_id_holder()、iter_dict_messages() 等轻量辅助;历史上用于同步 flow 的 agent_task_session() / wait_until_confirm() 已随 flows/ 目录移除。
续聊 / 确认 / 刷新等场景见 §7.1 run_agent_stream_raw 行为表。
6.4 出站消息¶
dialog() 会发送:
约束:
task_id必填。content与files至少一项非空。files存在时才会写入 data;仅附件对话可传content=""。
confirm() 会发送:
6.5 入站路由¶
IncomingRouterMixin 的处理规则:
- 除
call_agent外,入站帧必须能解析出task_id,否则忽略。 active_task用pre_task_id找原 link,再把新的data.task_id绑定到同一 link。call_agent用caller找原 link,再把callee绑定到同一 link。- 普通帧用
data.task_id或顶层task_id查task_id -> link_id。 - 查不到 link 的帧会记录“无路由丢弃”并丢弃。
因此任何能产生新 task_id 的动作,都必须立即绑定路由:
enter_agent返回初始task_idtask_refresh返回新task_id- 收到
active_task - 收到
call_agent
6.6 超时与重连¶
关键常量位于 ws/constants.py:
| 常量 | 当前值 | 说明 |
|---|---|---|
_INCOMING_QUEUE_MAXSIZE |
2000 |
每个 link 队列容量 |
_TASK_TO_LINK_MAX |
10000 |
task 路由表上限 |
_RECV_STALL_SECONDS |
3600 |
接收线程长期无任何帧时判定异常 |
_RECONNECT_BACKOFF_CAP_SEC |
5 |
重连退避上限 |
_RECONNECT_MIN_INTERVAL_SEC |
2 |
最小重连间隔 |
recv_stream() 默认:
- 首包超时
first_msg_timeout=60 - 后续空闲超时
subsequent_timeout=300 - 每
0.1s轮询 link 队列,并传播链路错误
7. SSE 流式链路¶
入口:modules/agent/service/user_agent/run_stream/service.py 的 run_stream_service()。
run_stream_service
├─ run_agent_stream_raw() # 生成上游 WS 原始帧
├─ AgentStreamAdapter.handle() # 上游 type → 前端事件
└─ sse_event(...) # 输出 SSE
7.1 run_agent_stream_raw¶
实现位置:streaming/raw.py。
| 场景 | 条件 | 行为 |
|---|---|---|
| 新任务 | 无 task_id |
WS session → enter_agent → 绑定 task → 先 yield task_start → 消费 enter 后上游帧 |
| 重新生成 | request_type == "refresh" |
WS session → task_refresh → 绑定新 task → recv_stream |
| 确认 | request_type == "confirm" |
WS session → ws.confirm(task_id) |
| 续聊 / 普通输入 | 其它有 task_id 的请求 |
WS session → ws.dialog(task_id, message, files) |
| 编辑回复 | modify_llm_response_stream |
WS session → 绑定原 task → HTTP modify → recv_stream |
若不是 confirm / init / refresh,且没有 message 和 files,会直接返回 message不能为空。
7.2 上游 type 映射¶
streaming/handlers/__init__.py 当前注册:
HANDLERS = {
"stream-start": handle_stream_start,
"stream": handle_stream,
"executing": handle_executing,
"confirm": handle_confirm,
"clarify": handle_clarify,
"executed": handle_executed,
"stream-end": handle_stream_end,
"active_task": handle_active_task,
"call_agent": handle_call_agent,
"rate_limit_blocked": handle_rate_limit_blocked,
"del_message": handle_del_message,
"user_message": handle_user_message,
}
处理器文件分布:
| 文件 | 处理的 type |
|---|---|
handlers/stream.py |
stream-start / stream / stream-end |
handlers/executing.py |
executing |
handlers/task_lifecycle.py |
confirm / clarify / executed / rate_limit_blocked |
handlers/system.py |
active_task / call_agent |
handlers/user_message.py |
user_message |
handlers/del_message.py |
del_message |
前端常见 SSE 事件:
| SSE type | 来源 | 内容 |
|---|---|---|
task_start |
run_agent_stream_raw |
新任务 task_id |
message_chunk |
stream |
主任务增量文本 |
note_chunk |
stream |
子任务 / 外部任务增量笔记 |
message_full |
executing 或 refine |
当前完整消息及按钮状态(含 show_actions) |
note_full |
executing.task_generated_data 或外部任务消息 |
笔记全文 |
task_update |
executing.task_progress/task_context |
节点进度 |
message_display |
executing 当前消息 display |
控制正文展示 |
deliverables_for_node |
executing 当前消息文件元数据 |
节点交付物文件(内部事件) |
deliverables_for_agent |
executing,node_name == "运行代码" |
内部 adapter 事件(不直接下发前端);经 events.py 转为 deliverable_data + 成功提示流 |
deliverable_data |
deliverables_for_node / deliverables_for_agent 落库后 |
节点/Agent 交付物,写入 agent_run_deliverable 并下发前端 |
active_task |
active_task |
活动任务切换(subagent 续跑时会替换 external_task_ids 中的旧 task) |
user_message |
user_message |
上游逻辑自动产生的用户侧消息(非真实用户输入) |
del_message |
del_message |
上游通知删除某条 assistant 消息(本地隐藏对应记录) |
rate_limit_blocked |
rate_limit_blocked |
上游限流,含 reason 正文后结束本轮 |
done |
confirm / executed / 编辑完成 / 限流 |
本轮结束 |
内部事件(不下发前端):clarify_waiting — 上游 clarify 通知需补充信息,仅设置运行记录的 waiting_clarify 标志并结束本轮 SSE。
已移除的产品侧形态:message_full.deliverable_confirm 确认按钮(SSE 不再下发该字段)。
须保留的活跃逻辑(勿当死代码清理):
deliverables_for_agent内部分支:handlers/executing.py在node_name == "运行代码"时产出内部事件 →run_stream/events.py→deliverables.py落库并下发deliverable_data与模拟成功消息流。- skills 占位:
adapter_helpers.py(start_skills_placeholder、absorb_skills_placeholder_stream_chunk、tick_skills_placeholder_tokens等)+handlers/stream.py/executing.py+run_stream/service.pytoken tick(0.5s);上游 skills 执行等待期间下发占位message_chunk(有工具状态时带status.type/status.token_text+ 增量正文;无工具状态时可见消息不带status)。display=false/ 子线 hidden 时与原先一致,改为message_full只下发 token。真实回复不再走假流,直接下发message_full。 - clarify 续跑占位:
start_clarify_skills_placeholder()在 clarify 续跑首帧启动 skills 占位(不置in_skills),由handlers/stream.py/executing.py调用。 user_message抑制:should_suppress_auto_user_message()— 最后一条可见消息仍是 user/tools、尚无 assistant 回复时,跳过上游自动user_message的落库与 SSE 下发。
7.3 executing 解析¶
主要解析函数:parser/executing.py。
当前消息定位路径:
parse_run_message_snapshot() 返回:
其中:
status来自message.metadata.status,缺省为pending。display缺省为True,显式false会保留;路由节点会被强制视为不展示。file_name/file_size由parse_last_message_file_meta()从当前消息读取,用于deliverables_for_node。
7.4 展示与按钮规则¶
平台指南说明 display 是上游消息字段;PE Agent 当前实现只用它控制消息正文展示:
按钮由 streaming/handlers/executing.py 根据当前消息计算:
role == "system":next/refresh/modify全部关闭。request_type == "init"且本次请求无用户文本/附件:交互按钮关闭。status == "completed":next关闭,但refresh/modify仍可按其它条件展示。- 内容含
点击“确认”:next强制开启。 - 内容含
这次有什么可以帮您?:next关闭。 - 正文含
<HRP_no_next>:next关闭。 - 正文含
```questions的message_full/note_full:next/modify关闭。 node_name == "运行代码"且role == "assistant":next关闭,并走deliverables_for_agent内部分支(见 §7.1)。show_actions:parser/text_extract.py从 assistant 正文中解析<show_right>/<show_left>/<show_down>标签,剥离后写入message_full.show_actions({right, left, down}),并落库到agent_run_message.show_actions。
confirm 拦截(handlers/task_lifecycle.py):
- 活跃路由节点(名称含
调用智能体或路由节点,且status为running/waiting_user)上的confirm会被拦截,不下发done。 - skills 占位期间及
auto_next && auto_run自动续跑场景有额外拦截逻辑(主/子线各自维护状态机)。
这意味着 PE Agent 的按钮策略不完全等同于平台原始字段;前端应以 SSE 的 message_full 字段为准。
8. 业务 Flow 调用模式¶
对外导出见 app/integrations/ai_power/__init__.py:
| 导出 | 典型场景 |
|---|---|
run_agent_stream_raw + AgentStreamAdapter |
用户 Agent 对话 SSE(run_stream/service.py) |
modify_llm_response_stream |
编辑 LLM 回复 SSE(modify.py) |
upload_file / download_file / replace_my_file |
聊天附件与交付物文件 |
pause_task / force_close_user_ws |
断连收尾、暂停上游任务 |
add_user |
注册时同步 AI Power 用户 |
未从 __init__.py 导出、由业务模块直接引用的 HTTP 能力:
| 模块 | 典型场景 |
|---|---|
http/files.read_directory |
Agent Tab placeholder、用户学习计划/自述加载(base_agent.py) |
http/user_llm_keys |
用户大模型密钥 CRUD(modules/user/service.py) |
http/lightrag.fetch_open_graphs |
知识图谱(modules/agent/service/user_agent/lightrag.py) |
主要业务入口:
modules/agent/service/user_agent/run_stream/:用户 Agent SSE 主链路。modules/agent/service/user_agent/modify.py:编辑回复 SSE。modules/agent/service/base_agent.py:Agent Tab 列表;通过read_directory加载入口介绍 placeholder、用户学习计划等。modules/user/service.py:用户大模型密钥 CRUD 中转。modules/agent/api/user_agent.py:GET /user-agent/lightrag/open_graphs知识图谱。app/tasks/agent.py:异步生成会话标题(agent.generate_task_name)。app/scheduler/:定时任务执行,复用run_stream_core。
9. 文件与扩展 HTTP 接口¶
实现位置:http/files.py、http/upload_helpers.py、http/user_llm_keys.py、http/lightrag.py。
9.1 文件接口¶
| 函数 | 平台接口 | 说明 |
|---|---|---|
upload_file(user, file) |
POST common/upload_file |
multipart/form-data,字段名由实现封装 |
download_file(user, file_name, task_id=None) |
GET common/download_file |
返回二进制 |
replace_my_file(user, ...) |
POST replace_my_file |
替换个人文件(笔记编辑等) |
read_directory(path, recursive=False) |
GET common/read-directory |
读取目录内容;使用 App token + get_lenient(),失败返回 {} |
read_directory 典型调用:
智能体入口介绍— 按文件名 stem 索引各 Tab 的 placeholder 文案。{phone}/学习文件夹— 读取学习计划.txt作为 planning Tab placeholder。{phone}/个人信息— 读取用户自述.txt,用于教学板块资料完整性提醒。
平台上传返回的 saved_path / file_size 会作为 WS dialog.data.files[] 的文件引用。对话只发附件时,content 可为空字符串。
9.2 用户大模型密钥¶
实现位置:http/user_llm_keys.py → modules/user/service.py → modules/user/api.py。
| HTTP | 集成函数 | 说明 |
|---|---|---|
POST /user/llm-keys |
create_user_llm_key |
新增密钥 |
GET /user/llm-keys |
list_user_llm_keys |
分页列表 |
PUT /user/llm-keys/{key_id} |
update_user_llm_key |
修改密钥 |
DELETE /user/llm-keys/{key_id} |
delete_user_llm_key |
删除密钥 |
均使用用户 token(build_user_headers),路径前缀由 AI_POWER_USER_LLM_KEYS_PATH 配置。
9.3 知识图谱(LightRAG)¶
实现位置:http/lightrag.py → modules/agent/service/user_agent/lightrag.py。
| HTTP | 集成函数 | 说明 |
|---|---|---|
GET /user-agent/lightrag/open_graphs |
fetch_open_graphs |
查询参数:label(默认 *)、max_depth(默认 3)、max_nodes(默认 1000) |
与常规 AI Power 接口不同:响应为直接 JSON 体(无 code/data 包装),由 get_direct() 处理;根地址同样走 AI_POWER_API_URL。
10. 标准时序¶
10.1 SSE 新任务:无 task_id¶
1. run_stream_service 创建/加载运行记录
2. run_agent_stream_raw → pool.session → WS connect
3. enter_agent → task_id → associate_task_with_link
4. yield task_start
5. recv_stream 消费 enter 后推送
6. AgentStreamAdapter 转为 SSE
7. confirm / executed 后下发 done
10.2 SSE 续聊、确认、刷新¶
续聊: session → 直接 ws.dialog(task_id, message/files)
确认: session → ws.confirm(task_id)
刷新: session → task_refresh(...) → 新 task_id → associate → recv_stream
编辑: session → associate 原 task_id → modify_llm_response → recv_stream 至 refine
10.3 客户端断开¶
SSE 使用 guard_sse_stream_with_client_disconnect 与 link_id_holder。客户端断开时,utils/http_sync_disconnect.py 会调用:
如果能拿到 per-user 锁,会结束指定 link;拿不到锁时会软终止对应消费端,避免底层生成器未关闭导致 session 的 finally 无法及时执行。
11. 排错¶
| 现象 / 日志 | 常见原因 | 处理 |
|---|---|---|
AI_POWER ws 无路由丢弃 |
enter_agent / task_refresh 后未绑定 task;或 active_task/call_agent 映射缺失 |
确认调用了 associate_task_with_link,并检查 task_id 类型 |
recv_stream 空闲超时 |
上游未推送、平台任务卡住、超时配置过小 | 查看上游任务状态;必要时调大 timeout |
当前链路无消息 |
link 队列暂时没有帧 | 若持续出现,检查 task 路由与平台是否仍在执行 |
获取 AI_POWER WebSocket 会话槽超时 |
同一用户 session attach/release 锁被占用,常见于 SSE 未正常收尾 | 检查断连处理与 force_close_user_ws |
| 接收线程死亡 / pending error | 上游 WS 断开或协议异常 | 依赖重连;多次失败后会向 link 消费端抛统一错误 |
HTTP code != 200 |
平台业务错误、token 过期、路径或 payload 不匹配 | 查看 app.integrations.ai_power.http.client 日志中的 payload |
| 文件上传失败 | 上传仍带 JSON Content-Type 或字段不符 |
使用 post_file() / upload_file(),不要手写请求 |
| 前端按钮状态与平台字段不一致 | PE Agent 在 SSE 层二次计算按钮 | 以前端收到的 message_full 字段为准 |
| 上游自动 user_message 未出现 | 上一条可见消息尚无 assistant 回复,被 should_suppress_auto_user_message 抑制 |
预期行为;待 assistant 回复后再收后续自动消息 |
| LightRAG 接口失败 | AI_POWER_API_URL 未配置或路径错误 |
检查 AI_POWER_API_URL 与 AI_POWER_LIGHTRAG_OPEN_GRAPHS_PATH |
| read_directory 返回空 | 目录不存在或 App token 无效 | 查看 [read_directory] 日志;失败时 get_lenient 静默返回 {} |
常用 logger:
app.integrations.ai_power.auth.token_managerapp.integrations.ai_power.http.clientapp.integrations.ai_power.agents.tasksapp.integrations.ai_power.wsapp.integrations.ai_power.ws_pool
12. 开发约定¶
推荐:
- 核心能力从
app.integrations.ai_power导入公开函数;扩展 HTTP 可引用http/files、http/user_llm_keys、http/lightrag。 - 新任务使用
get_ai_power_ws_pool().session(user),并在enter_agent/task_refresh后associate_task_with_link(见streaming/raw.py)。 - 所有 WS 操作显式传
link_id=sess.link_id。 enter_agent、task_refresh后立即associate_task_with_link。- SSE 入口传入
link_id_holder,并使用断连保护。 - 解析
task_id时使用task_id_key()/same_task_id(),避免 int/string 混用。
禁止:
- 业务层绕过连接池自建 WS。
- 在接收线程外直接
recv()。 - 多请求场景省略
link_id。 - 业务层直接拼 AI Power URL 或直接调用
requests。 - 把平台原始按钮状态直接透给前端,绕过
AgentStreamAdapter。
13. 目录索引¶
app/integrations/ai_power/
├── __init__.py
├── auth/
│ ├── app_token.py
│ ├── token_manager.py
│ └── user.py
├── http/
│ ├── base_url.py
│ ├── client.py # get/post/put/delete/get_lenient/get_direct/get_raw/post_file
│ ├── files.py # upload/download/read_directory/replace_my_file
│ ├── upload_helpers.py
│ ├── user_facing.py
│ ├── user_llm_keys.py # 用户大模型密钥 CRUD
│ └── lightrag.py # 知识图谱 open_graphs
├── agents/
│ └── tasks.py # enter_agent / task_refresh / modify / pause
├── parser/
│ ├── executing.py
│ ├── deliverables.py
│ ├── task_progress.py
│ └── text_extract.py # show_actions / show_content / questions 解析
├── streaming/
│ ├── adapter.py
│ ├── adapter_helpers.py
│ ├── adapter_context.py
│ ├── raw.py
│ └── handlers/
│ ├── __init__.py
│ ├── stream.py
│ ├── executing.py
│ ├── task_lifecycle.py
│ ├── system.py
│ ├── user_message.py
│ └── del_message.py
├── ws/
├── ws_pool/
└── task_ids.py
相关入口:
- 配置:
app/core/config.py - 路由注册:
app/main.py(auth/user/base-agent/user-agent/open) - 用户注册:
app/modules/auth/service.py - Agent SSE:
app/modules/agent/service/user_agent/run_stream/service.py - 编辑回复:
app/modules/agent/service/user_agent/modify.py - Agent Tab / placeholder:
app/modules/agent/service/base_agent.py - 用户 LLM Keys:
app/modules/user/service.py - 知识图谱:
app/modules/agent/service/user_agent/lightrag.py - 队列消费:
app/queue/runner.py(main.lifespan内置;调试可用python -m app.queue.worker) - 客户端断开:
app/utils/http_sync_disconnect.py
实现细节以代码为准;平台协议字段与接口说明见 PE Agent 集成(平台对接指南)。